从then()返回值或Promise.resolve有什么区别


314

之间有什么区别?

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()。因此,代码太多了,因此首先是上面的示例。


1
您看到什么“不同行为”?这两个示例均应工作且行为大致相同。所述Promise.resolve()在第二个例子中是不必要的。
JLRishe 2014年

4
@pixelbits从then处理程序返回一个承诺没有任何错误,事实上,这是您可以做到的承诺规范的关键方面。

请注意,这可与任意嵌套的thens一起使用-的“其他语言”一词then既是a map又是a flatMap
本杰明·格伦鲍姆

1
在第2行中,为什么您必须调用res(“ aaa”),为什么不能返回“ aaa”就足够了,并且Promise捕获了resolve()的方式也与捕获拒绝()的异常的方式相同?
Sam Liddicott

1
@SamLiddicott有相同的问题,而地雷则更加复杂:new Promise((res, rej) => { return fetch('//google.com').then(() => { return "haha"; }) }).then((result) => alert(result));此代码将挂起(永远无法解决)。但是如果我更改return "haha";为,return res("haha");它将起作用并警告“ haha​​”。fetch()。then()是否已经将“ haha​​”包装为已解决的承诺?
Shaung Cheng

Answers:


138

规则是,如果then处理程序中的函数返回一个值,则promise将使用该值进行解析/拒绝;如果函数返回一个promise,则发生的情况是,下一个then子句将成为该函数返回的promise的then子句,所以,在这种情况下,第一个例子落空的正常序列和打印出的值作为人们所预料的,当你这样做,在第二个例子中,被返回的承诺对象的则是那个被当链接调用(出于所有意图和目的)。其实际工作方式将在下面详细介绍。thensPromise.resolve("bbb")then

引用Promises / A +规范:

承诺解决程序是一个抽象的操作,将承诺和值作为输入,我们将其表示为[[Resolve]](promise, x)如果x是可能的,则在x的行为至少类似于诺言的假设下,尝试使诺言采用的状态x。否则,它将用值实现承诺x

只要允许公开实现公开Promises / A +兼容then方法,此实现就允许承诺实现实现互操作。它还允许Promises / A +实现使用合理的then方法“整合”不合格的实现。

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

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

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


4
“采用其状态”是一种简洁有效的方式,用于在then处理程序返回承诺时表达行为。+1作为规格参考。

69
实际上-规范的相关部分是在能力和价值上都这样[[Resolve]]被称呼的事实,then因此本质上它用诺言包装了价值,因此return "aaa"与-相同,return Promise.resolve("aaa")并且return Promise.resolve("aaa")相同return Promise.resolve(Promise.resolve("aaa"))--因为resolve是幂等的,因此更多地将其称为价值比一次具有相同的结果。
Benjamin Gruenbaum 2014年

8
@Benjamin Gruenbaum是否意味着回报,"aaa"并且在任何情况下return Promise.resolve("aaa")都可以互换then
CSnerd

9
是的,这就是它的意思。
本杰明·格林本

118

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

A)当x是值(数字,字符串等)时:

  1. return x 相当于 return Promise.resolve(x)
  2. throw x 相当于 return Promise.reject(x)

B)什么时候x是已经解决的承诺(不再待处理):

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

C)何时x是一个尚待履行的承诺:

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

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


92

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

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

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

在第二个示例中,您返回一个Promise,该Promise将立即由value解析"bbb",因此将"bbb"被传递到下一个then()处理程序中。(Promise.resolve()这里是多余的)。

结果是一样的。

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


1
好答案!怎么样Promise.resolve();VS return;
FabianTe '18年

2
@FabianTe除了用undefined代替之外,那些也将具有相同的效果"bbb"
JLRishe

51

您已经有了一个很好的正式答案。我想我应该加一个简短的。

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

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

因此,对于诺言或纯值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
Sampgun

在99.99%的情况下,它与Promise.resolve(x)毫无关系。(0.001%是我们处于with对象或代理的阻塞中,且该对象或代理具有x引发异常的属性访问器。在这种情况下,Promise.resolve(x)会导致引发错误,但Promise.resolve().then(function(){ return x; });由于引发了错误而将被拒绝)在then)中。
Benjamin Gruenbaum

您链接了一个空的闪电战,或者您没有保存。无论如何,我不是在谈论语句之间的差异。我在讲的正是我写的东西。为了更清楚一点,这是我正在谈论的摘录:if (validator) { Promise.resolve().then(() => { this._cdRef.markForCheck(); }); }。这里的承诺没有分配,那么有什么意义呢?超时是否会(或多或少)具有相同的效果?
S弹枪

1
在所有同步代码发生之后但在任何I / O发生之前,它异步执行调用。这就是所谓的“ microtick语义”。
Benjamin Gruenbaum

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.