【问题标题】:Extra promise at start and Extra promise at end开始时的额外承诺和结束时的额外承诺
【发布时间】:2018-02-27 08:03:32
【问题描述】:

Promise 的新手,所以请随意冗长。

我正在编写一个函数“extra_promises_at_start_and_end”,它返回一个承诺做某事。

这个函数可能会立即知道它将失败(即:返回一个被拒绝的承诺)。问题 1:是否有类似 Promise.give_me_a_rejected_promise(..) 的东西,还是我必须像我的代码一样创建一个承诺并拒绝它?

同样,我的函数“extra_promises_at_start_and_end”调用其他返回承诺的函数。在此异步工作链结束时,我需要进行一些最终处理。问题 2a/2b:由于我的函数返回一个 Promise,我需要创建一个 Promise 来完成这最后一点工作。我需要创建一个承诺并立即接受或拒绝它是否正确?有没有 Promise.give_me_a_rejected_promise(..).

我的代码按预期工作,只是感觉我遗漏了一些东西,因此生成了冗余代码。

有问题的代码:

// this is the function that may have redundant code
// see question 1 and 2
function extra_promises_at_start_and_end() {
    // fake out some module scope variable that indicates if this call is allowed to proceed or not
    let ok_to_proceed = Math.random() > 0.5

    // this function "extra_promises_at_start_and_end returns" a promise, 
    // Question 1: I need to create a Promise just to reject it immediatly?
    if (!ok_to_proceed) {
        return new Promise((resolve, reject) => { reject("failed before starting anything") }) // feels wrong
    }

    // do 5 things in sequence
    return another_module_promise_to_do_something(1).then(() => {
        return another_module_promise_to_do_something(2)
    }).then(() => {
        return another_module_promise_to_do_something(3)
    }).then(() => {
        return another_module_promise_to_do_something(4)
    }).then(() => {
        return another_module_promise_to_do_something(5)
    }).then(() => {
        // need to do something after the above 5 tasks are done, 

        console.log("doing something after all 5 things are done")

        // this function "extra_promises_at_start_and_end" returns a promise, 
        // Question 2a: I need to create a promise just to resolve it immediatly?
        return new Promise((resolve, reject) => { resolve(); }) // feels wrong
        }).catch((id) => {
            // this function extra_promises_at_start_and_end returns a promise, 
            // Question 2b: I need to create one just to reject it immediatly?
            return new Promise((resolve, reject) => { reject(id); }) // feels wrong
        })
}

这段代码的调用者期待一个承诺。

// run the test
console.log("calling something that will return a promise to let me know when it's done");
extra_promises_at_start_and_end()
    .then(() => {
        console.log("done :)")
    }).catch((id) => { console.log("failed id = " + id) })

最后,一个用于测试我的函数的存根

// pretend this is a complex task (ie: not suitable for inlining)
// done by some other module
// it returns a promise
function another_module_promise_to_do_something(id) {
    console.log("starting " + id)

    let P = new Promise((resolve, reject) => {
        console.log("  inside promise " + id)

        setTimeout(() => {
            if (Math.random() > 0.1) {
                console.log("  finished " + id);
                resolve();
            } else {
                console.log("  failed " + id)
                reject(id);
            }
        }, Math.random() * 1000)
    })

    return P;
}

如果这是应该的方式,那么请告诉我,我将停止寻找使用 Promise 的正确方式。

【问题讨论】:

标签: javascript node.js promise


【解决方案1】:

Promisethen()catch() 函数返回 Promise

您的最后一大段代码确实是多余的。如果您需要在第 5 次链接调用 then() 之后进行任何处理,您可以链接另一个 then()

这里有一个更简单的代码版本来说明:

const countFromOneToFive = () => {
  if (Math.random() > 0.5) {
    return Promise.reject("Cosmic radiation ruined your promises. Great.");
  }

  return Promise.resolve([])
    .then((countToFive) => {
      countToFive.push(1);
      return countToFive;
    })
    .then((countToFive) => {
      countToFive.push(2);
      return countToFive;
    })
    .then((countToFive) => {
      countToFive.push(3);
      return countToFive;
    })
    .then((countToFive) => {
      countToFive.push(4);
      return countToFive;
    })
    .then((countToFive) => {
      countToFive.push(5);
      return countToFive;
    });
};

countFromOneToFive()
  .then((countToFive) => {
    countToFive.forEach((number) => console.log(number));
  })
  .catch((error) => {
    console.log(error, "Curses!");
  });

您可以使用Promise.reject() 来返回被拒绝的Promise。这在底部的 catch 语句中处理。

您可以根据需要使用任意数量的then() 调用来完成所有处理。您可以在最后的then() 之后返回以拥有Promise。从那里开始,像任何承诺一样对待它,并在你认为合适的时候附加 then()s 和 catch()s。

【讨论】:

    【解决方案2】:

    1:是否有类似 Promise.give_me_a_rejected_promise(..) 的东西,还是我必须像我的代码一样创建一个承诺并拒绝它?

    喜欢Promise.reject(err)

    // 问题 2a:我需要创建一个承诺来立即解决它?

    在您的代码中写入这一点的位置位于承诺链中。您根本不需要做任何事情(在这种情况下),即可返回已解决的 Promise,除非可能不是 throwing。

    此 Promise 将解析为您返回的任何值,undefined 除外。如果您返回 undefined(显式或隐式),此 Promise 将解析为 Promise 链中的最后一个值。
    仅当您需要明确解析为 undefined 时,您必须解析为 return Promise.resolve()

    // 问题2b:我需要创建一个只是为了立即拒绝它?

    仍然在 Promise 链中:由于被拒绝的值就像同步代码中抛出的错误,你需要做的就是throw

    但这在你问的上下文中是没有意义的。为什么要捕获错误,只是为了立即抛出相同的错误,而不在该捕获块中执行任何其他操作。

    所以你的代码可能是这样的

    function extra_promises_at_start_and_end() {
        // fake out some module scope variable that indicates if this call is allowed to proceed or not
        let ok_to_proceed = Math.random() > 0.5
    
        if (!ok_to_proceed) {
            return Promise.reject("failed before starting anything");
        }
    
        // do 5 things in sequence
        return another_module_promise_to_do_something(1)
            .then(() => another_module_promise_to_do_something(2))
            .then(() => another_module_promise_to_do_something(3))
            .then(() => another_module_promise_to_do_something(4))
            .then(() => another_module_promise_to_do_something(5))
            .then(() => {
                // need to do something after the above 5 tasks are done, 
    
                console.log("doing something after all 5 things are done")
    
                return null; //so the previous value is no longer propagated by this Promise
            })
            //.catch(id => { throw id }) //is pointless.
    }
    

    当您说“此 Promise 将解析为您返回的任何值”时。所以返回 new Promise((resolve, reject) => { resolve 100}).then .... blaw blaw blaw 与 100.then .. blaw blaw blaw 相同?

    不完全是。在 Promise 链中,返回像 100 这样的普通值或解析为 100 (如 return Promise.resolve(100) 的 Promise 在结果中是等价的......

    var foo1 = somePromise.then(() => {
        //do something
        return 100
    })
    //is equivalent in result to
    var foo2 = somePromise.then(() => {
        //do something
        return Promise.resolve(100);
    })
    //or to
    var foo3 = somePromise.then(() => {
        //do something
        return new Promise(resolve => resolve(100));
    })
    

    foo1foo2foo3 都是在 somePromise 完成后解析为值 100 的承诺。结果是等价的。

    ...但您不能在号码上拨打then()

    //you can do
    somePromise.then(() => {
        //do something
        return 100
    }).then(...)
    
    //or sometimes you want to do
    somePromise.then((value) => {
       //usually because you need `value` inside `.then(...)`
        return somethingAsync().then(...)
    })
    
    //but you can NOT do 
    somePromise.then(() => {
        //do something
        return 100.then(...)
    })
    

    【讨论】:

    • @grabbag,不完全是。我已经扩展了答案来解释这一点
    【解决方案3】:

    我学到的是:

    • Promise.resolve(value) 方法返回一个使用给定值解析的 Promise 对象。因此,任何调用我的函数的人都可以对响应执行 then 操作。

    • Promise.reject(reason) 方法返回一个因给定原因被拒绝的 Promise 对象。因此,任何链接都会根据需要失败。

    • then 中的任何返回值都将被封装在一个 Promise 中。感觉像这样模糊了意图。所以不使用。

    我的新功能如下:

    function promise_something() {
        // fake out some module scope variable that indicates if this call is allowed to proceed or not
            let ok_to_proceed = Math.random() > 0.5
    
    
    
     if (!ok_to_proceed) {
            return Promise.reject("failed before starting anything") 
        }
    
        // do 5 things in sequence
        return another_module_promise_to_do_something(1).then(() => {
            return another_module_promise_to_do_something(2)
        }).then(() => {
            return another_module_promise_to_do_something(3)
        }).then(() => {
            return another_module_promise_to_do_something(4)
        }).then(() => {
            return another_module_promise_to_do_something(5)
        }).then(() => {
            // need to do something after the above 5 tasks are done, 
    
            console.log("doing something after all 5 things are done")
    
            return Promise.resolve()
    }
    

    【讨论】:

      猜你喜欢
      • 2016-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-07
      • 2021-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多