为什么Promise构造函数需要一个调用' resolve'完成后,然后'然后'不 - 它返回一个值而不是?

时间:2015-07-09 17:13:14

标签: javascript promise ecmascript-6 es6-promise

当我开始研究Promise时,我的理解已停止在我未发现讨论的以下问题上(我发现只有Promise构造函数的具体讨论,{{1 }}' Promise'功能 - 但不是比较其设计模式的讨论。)

1。 then构造函数

From the MDN documentation我们使用了Promise构造函数(添加了我的评论):

Promise
  

具有两个参数new Promise(function(resolve, reject) { ... }); // <-- Call this Stage 1 resolve的函数对象。首先   论证履行了承诺,第二个论点拒绝承诺。我们可以   一旦我们的操作完成,就调用这些函数。

2。 reject功能

转到可以在then对象上调用的then函数(返回一个新的Promise对象),我们有{{3 (添加了我的评论): :

Promise
  

链接

     

因为p.then(onFulfilled, onRejected); 方法返回Promise,所以您可以轻松地进行链接   调用

then

我的问题

从上面的代码片段中,我很清楚值传递给第1阶段的var p2 = new Promise(function(resolve, reject) { resolve(1); // <-- Stage 1 again }); p2.then(function(value) { console.log(value); // 1 return value + 1; // <-- Call this Stage 2 }).then(function(value) { console.log(value); // 2 }); 函数(在第二次出现resolve - 下面( 2),上面)被传递到下一个阶段(后面的第一个resolve函数在相同的代码片段中)。 第1阶段没有返回值。但是,第2阶段的返回值会在此之后传递到下一个阶段(第二个{{1}功能)。

创建then的设计模式与现有承诺(也返回then)上Promise函数的使用之间是否缺乏对应关系,只是一个历史的侥幸(一个需要调用一个回调但什么都不返回,另一个返回一个值,但不会调用回调)?

或者我错过了then构造函数使用与Promise函数不同的设计模式的根本原因?

4 个答案:

答案 0 :(得分:26)

Bergi's answer很棒,对我很有帮助。这个答案是对他的补充。为了可视化Promise()构造函数和then()方法之间的关系,我创建了这个图。我希望它可以帮助某些人......甚至可能在几个月之后帮助我。

这里的主要思想是传递给Promise()构造函数的“executor”函数设置动作中的任务,设置承诺的状态;而传递给then()的处理程序将对承诺的状态作出反应。

Diagram: Promise() executor vs. then() method (代码示例改编自Jake Archibald's classic tutorial。)

这是对事物如何运作的高度简化的看法,遗漏了许多重要的细节。但我认为如果能够抓住对预期目的的良好概述,它将有助于避免在进入细节时产生混淆。

一些选定的细节

立即调用执行程序

一个重要的细节是传递给Promise()构造函数的执行函数被称为立即(在构造函数返回promise之前);而传递给then()方法的处理函数直到以后(如果有的话)才会被调用。

Bergi提到了这一点,但是我想在不使用a / synchron括号的情况下重申它,如果你不仔细阅读可能会混淆:函数调用某些异步的东西之间的区别被异步调用很容易在通信中被掩盖。

resolve()不是onFulfill()

我想强调一个细节,因为它让我困惑了一段时间,是resolve()reject()回调传递给Promise()构造函数的执行函数不是后来传递给then()方法的回调。回想起来,这似乎是显而易见的,但明显的联系让我在圈子里旋转了太久。肯定有一种联系,但它是一个松散的,动态的。

相反,resolve()reject()回调是由“system”提供的函数,并由Promise构造函数传递给执行函数。你创造了一个承诺。调用resolve()函数时,系统代码会执行,可能会更改promise的状态,并最终导致异步调用onFulfilled()回调。不要将resolve()称为调用onFulfill()的紧密包装器!

答案 1 :(得分:23)

Promise构造函数与then方法之间没有对应关系,因为它们是两个独立的东西,专为不同目的而设计。

Promise构造函数仅用于promisifying 1 异步函数。实际上,正如您所说,它建立在调用 resolve / reject回调到异步发送值的基础上,并且没有返回值情况下。

Promise构造函数本身确实采用了这个“解析器”回调(它同步传递resolvereject)实际上是旧的延迟模式的增强,并且与then回调相比,没有预期的相似性

var p = new Promise(function(res, rej) {    |    var def = Promise.Deferred();
    setTimeout(res, 100);                   |    setTimeout(def.resolve, 100);
});                                         |    var p = def.promise;

相比之下,then回调是经典的异步回调,additional feature可以returnp.then(function(val) { … }); 。它们被异步调用接收值。

Promise

总结差异:

  • then是构造函数,而Promise是方法
  • then需要一次回调,而Promise最多需要两次
  • then同步调用其回调,而Promise以异步方式调用其回调
  • then总是调用它的回调,
    Promise可能不会调用其回调(如果未履行承诺/拒绝承诺)
  • then传递解析/拒绝回调承诺的功能,
    Promise传递了在
  • 上调用的承诺的结果值/拒绝原因
  • reject调用其回调以执行副作用(调用resolve / then),
    Promise.resolve调用其回调结果值(用于链接)

是的,两者都会返回承诺,尽管它们与许多其他功能(Promise.rejectfetchPromise,...)共享该特征。事实上,所有这些都基于then构造函数提供的相同的承诺构造和解析/拒绝功能,尽管这不是它们的主要目的。 onFulfilled基本上提供了将onRejected / Promise回调附加到现有承诺的功能,该承诺对18m构造函数而言是相当直接的。

两者都利用回调只是巧合 - 不是历史的侥幸,而是语言特征的共同适应。

1:理想情况下,您永远不需要这个,因为所有本机异步API都会返回承诺

答案 2 :(得分:6)

promise构造函数执行器函数的重点是将解析和拒绝函数传播给非承诺使用代码,将其包装并转换为使用promise。如果你只想将它限制为同步函数,那么是的,可能已经使用了函数的返回值,但这本来是愚蠢的,因为有用的部分是传播解析器并拒绝函数到以后实际运行的代码(返回后的方式),例如传递给某个异步API的回调。

答案 3 :(得分:4)

受到之前答案的启发(我将解决最令我困惑的部分):

Promise构造函数中的resolvereject参数不是您定义的函数。将它们视为嵌入到异步操作代码中的钩子(通常是resolve成功响应,reject有失败原因),因此javascript有一种方法可以最终将Promise标记为已实现或拒绝取决于您的异步操作的结果;一旦发生这种情况,您在then(fun1, fun2)中定义的相应函数将被触发使用Promise(fun1(success_response)fun2(failure_reason),具体取决于Promise是否已实现/已拒绝。由于fun1fun2是普通的旧javascript函数(它们恰好将异步操作的未来结果作为参数),因此它们return值(可以是undefined如果你没有明确地返回)。

另见Mozilla的精彩文章:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise