【问题标题】:What's the difference between returning value or Promise.resolve from then()then() 返回值或 Promise.resolve 有什么区别
【发布时间】:2015-02-27 04:45:10
【问题描述】:

有什么区别:

new Promise(function(res, rej) {
    res("aaa");
  })
  .then(function(result) {
    return "bbb";
  })
  .then(function(result) {
    console.log(result);
  });

还有这个:

new Promise(function(res, rej) {
    res("aaa");
  })
  .then(function(result) {
    return Promise.resolve("bbb");
  })
  .then(function(result) {
    console.log(result);
  });

我在问,因为我使用 Angular 和 $http 服务与链接 .then() 获得了不同的行为。代码有点多,所以先看上面的例子。

【问题讨论】:

  • 你看到了什么“不同的行为”?这两个示例都应该工作并且行为大致相同。第二个示例中的Promise.resolve() 是不必要的。
  • @pixelbits 从then 处理程序返回承诺没有任何问题,事实上,这是承诺规范的一个关键方面,您可以这样做。
  • 在第 2 行为什么你必须调用 res("aaa"),为什么不能返回 "aaa" 就足够了,并且 Promise 捕获 resolve() 的方式与它捕获的相同拒绝()的例外?
  • @SamLiddicott 有同样的问题,而地雷有点复杂:new Promise((res, rej) => { return fetch('//google.com').then(() => { return "haha"; }) }).then((result) => alert(result)); 这个代码只会挂起(不会永远解决)。但是,如果我将return "haha"; 更改为return res("haha");,那么它将起作用并提醒“哈哈”。 fetch().then() 不是已经将“haha”包装成一个已解决的承诺了吗?
  • @ShaungCheng 如果你使用 Promise 构造函数,你应该调用传递的函数的res 参数而不是返回结果。返回传递给 Promise 构造函数的函数内部的任何内容都将被忽略

标签: javascript angularjs promise q


【解决方案1】:

唯一的区别是,当您执行return Promise.resolve("bbb") 时,您创建了一个不必要的承诺。从onFulfilled() 处理程序返回一个承诺会启动promise resolution。这就是promise chaining 的工作原理。

【讨论】:

    【解决方案2】:

    简单来说,在 then 处理函数内部:

    A) 当x 是一个值(数字、字符串等)时:

    1. return x 等价于 return Promise.resolve(x)
    2. throw x 等价于 return Promise.reject(x)

    B) 当x 是一个已经结算的Promise(不再等待处理)时:

    1. return x 等同于 return Promise.resolve(x),如果 Promise 已经解决。
    2. 如果 Promise 已被拒绝,return x 等效于 return Promise.reject(x)

    C) 当x 是一个待处理的 Promise 时:

    1. return x 将返回一个待处理的 Promise,并将在随后的 then 上进行评估。

    Promise.prototype.then() docs 上阅读有关此主题的更多信息。

    【讨论】:

    • 【B) 2.】应该是“throw x”?
    • @Lancer.Yan 并非如此,B 表示return 的行为会根据 Promise 的已结算值而变化。编写代码时,您真的不知道它是否会解决或拒绝。当然,您可以使用 try-catch 来处理拒绝,然后重新抛出,但情况不同。
    【解决方案3】:

    您的两个示例的行为应该几乎相同。

    then() 处理程序中返回的值成为从该then() 返回的承诺的分辨率值。如果.then 中返回的值是一个promise,则then() 返回的promise 将“采用该promise 的状态”并像返回的promise 一样解决/拒绝。

    在您的第一个示例中,您在第一个then() 处理程序中返回"bbb",因此"bbb" 被传递到下一个then() 处理程序。

    在您的第二个示例中,您返回一个立即使用值 "bbb" 解析的承诺,因此 "bbb" 被传递到下一个 then() 处理程序。 (这里的Promise.resolve() 是无关的)。

    结果是一样的。

    如果您可以向我们展示一个实际表现出不同行为的示例,我们可以告诉您为什么会发生这种情况。

    【讨论】:

    • 不错的答案! Promise.resolve();return; 怎么样?
    • @FabianTe 这些也会有相同的效果,除了 undefined 而不是 "bbb"
    【解决方案4】:

    规则是,如果 then 处理程序中的函数返回一个值,则承诺会使用该值解析/拒绝,如果函数返回一个承诺,发生的情况是,下一个 then 子句将是 函数返回的 promise then 子句,因此,在这种情况下,第一个示例将通过 thens 的正常序列并打印出人们可能期望的值,在第二个示例,当您执行Promise.resolve("bbb")'s 时返回的承诺对象是链接时调用的then(用于所有意图和目的)。下面更详细地描述了它的实际工作方式。

    引用 Promises/A+ 规范:

    promise 解析过程是一个抽象操作,将 promise 和 value 作为输入,我们将其表示为[[Resolve]](promise, x)如果x 是一个thenable,它会尝试让promise采用x 的状态,假设x 的行为至少有点像promise。否则,它会以 x 的值履行承诺。

    对 thenables 的这种处理允许 Promise 实现互操作,只要它们公开一个符合 Promises/A+ 的 then 方法。它还允许 Promises/A+ 实现使用合理的 then 方法“吸收”不符合要求的实现。

    这里要注意的关键是这一行:

    如果x 是一个承诺,采用它的状态 [3.4]

    链接:https://promisesaplus.com/#point-49

    【讨论】:

    • “采用它的状态”是一种简洁而有用的方式来表达then 处理程序返回承诺时的行为。规格参考 +1。
    • 实际上 - 这里规范的相关部分是 [[Resolve]]thenables 和值上都被调用,所以本质上它用承诺包装了一个值,所以 return "aaa" 是相同的因为 return Promise.resolve("aaa")return Promise.resolve("aaa")return Promise.resolve(Promise.resolve("aaa")) 相同 - 因为 resolve 是幂等的,在一个值上多次调用它具有相同的结果。
    • @Benjamin Gruenbaum 是否意味着 return "aaa"return Promise.resolve("aaa") 在任何情况下都可以在 thenables 中互换?
    • 是的,就是这个意思。
    • “如果 then 处理程序中的函数返回一个值,则承诺会使用该值解决/拒绝,”我认为答案应该澄清承诺何时解决以及何时拒绝而不是说“承诺解决/拒绝”。
    【解决方案5】:

    你已经得到了一个很好的正式答案。我想我应该添加一个简短的。

    以下内容与Promises/A+ promises 相同:

    • 调用 Promise.resolve(在您的 Angular 案例中为 $q.when
    • 调用 promise 构造函数并在其解析器中解析。在你的情况下是new $q
    • then 回调返回一个值。
    • 在具有值的数组上调用 Promise.all,然后提取该值。

    因此,对于 promise 或普通值 X,以下内容都是相同的:

    Promise.resolve(x);
    new Promise(function(resolve, reject){ resolve(x); });
    Promise.resolve().then(function(){ return x; });
    Promise.all([x]).then(function(arr){ return arr[0]; });
    

    毫不奇怪,promise 规范基于Promise Resolution Procedure,它可以轻松实现库之间的互操作(如 $q 和本机 promise),让您的生活更轻松。每当可能发生承诺解决方案时,都会发生解决方案,从而创建整体一致性。

    【讨论】:

    • 请问Promise.resolve().then(function(){ return x; }); 的意义何在?我发现了一个类似的片段(它在then 块内调用了一个函数)。我认为它或多或少像做超时,但它有点快。 jsben.ch/HIfDo
    • 在 99.99% 的情况下它与 Promise.resolve(x) 相同是没有意义的。 (0.001% 是我们在 with 块中使用 x 属性访问器抛出异常的对象或代理。在这种情况下, Promise.resolve(x) 会导致抛出错误,但 Promise.resolve().then(function(){ return x; }); 会是一个被拒绝的承诺,因为错误是在 then) 中引发的。
    • 你链接了一个空的闪电战,或者你没有保存。无论如何,我不是在谈论陈述之间的差异。我说的正是我写的东西。为了更清楚,这就是我所说的 sn-p:if (validator) { Promise.resolve().then(() => { this._cdRef.markForCheck(); }); }。这里没有分配承诺,那有什么意义呢?超时是否会(或多或少)产生相同的效果?
    • 它在所有同步代码发生之后但在任何 I/O 发生之前异步执行调用。这就是所谓的“microtick 语义”。
    猜你喜欢
    • 1970-01-01
    • 2021-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-02
    • 2022-08-06
    • 2011-12-24
    • 2020-02-01
    相关资源
    最近更新 更多