41

当我投入研究Promises 时,我对以下我没有讨论过的问题的理解已经停止(我发现的只是对Promise构造函数和Promise' then' 函数的具体讨论 - 但不是比较它们的设计模式的讨论)。


1.Promise构造函数

从 MDN 文档中,我们使用了 Promise 构造函数(添加了我的评论):

new Promise(function(resolve, reject) { ... }); // <-- Call this Stage 1

具有两个参数的函数对象resolvereject. 第一个参数实现了承诺,第二个参数拒绝了它。一旦我们的操作完成,我们就可以调用这些函数。


2.then功能

继续讨论then可以在对象上调用的函数Promise(它返回一个新Promise对象),我们有文档描述的以下函数签名(添加了我的评论):

p.then(onFulfilled, onRejected);

链接

因为该then方法返回一个 Promise,所以您可以轻松地链接 then 调用。

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第 1 阶段中的函数的值(在第二次出现resolve- 低于 (2),上面)被传递到下一个阶段(第 1 阶段之后的第一个then函数相同的代码片段)。 第 1 阶段没有返回值。 但是,第 2 阶段的返回值被传递到之后的下一个阶段(第二个then函数)。

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

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

4

5 回答 5

39

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

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

图:Promise() 执行器与 then() 方法 (代码示例改编自Jake Archibald 的经典教程。)

这是对事物运作方式的高度简化视图,省略了许多重要细节。但我认为,如果一个人能够很好地掌握预期目的,这将有助于避免在进入细节时产生混淆。

一些选定的细节

执行者立即被调用

一个重要的细节是传递给Promise()构造函数的执行器函数被立即调用(在构造函数返回承诺之前);而传递给该方法的处理函数将在以后(如果有的话)then()被调用。

Bergi 提到了这一点,但我想在不使用术语 a/synchronously 的情况下重述它,如果您不仔细阅读可能会感到困惑:异步调用某物的函数与异步调用的函数之间的区别很容易在通信中掩盖.

resolve()不是onFulfill()

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

相反,resolve()andreject()回调是由 "system" 提供的Promise函数,并在您创建承诺时由构造函数传递给 executor 函数。当resolve()函数被调用时,系统代码会被执行,这可能会改变 Promise 的状态,并最终导致onFulfilled()异步调用回调。不要认为 callresolve()是 call 的紧密包装onFulfill()

于 2017-02-02T14:39:30.213 回答
32

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回调是经典的异步回调,您可以从它们中获得附加功能。return它们被异步调用接收值。

p.then(function(val) { … });

总结一下区别:

  • Promise是构造函数,whilethen是方法
  • Promise需要一个回调,而then最多需要两个
  • Promise同步调用其回调,而then异步调用其回调
  • Promise总是调用它的回调,
    then可能不会调用它的回调(如果承诺没有被履行/拒绝)
  • Promise将解决/拒绝承诺的能力传递给回调,
    then传递被调用的承诺的结果值/拒绝原因
  • Promise调用其回调以执行副作用(调用reject/ resolve),
    then调用其回调以获取其结果值(用于链接)

是的,两者都返回了 Promise,尽管它们与许多其他函数(Promise.resolvePromise.rejectfetch、 ...)具有相同的特征。事实上,所有这些都基于构造Promise函数提供的相同的承诺构造和解析/拒绝功能,尽管这不是它们的主要目的。then基本上提供了将onFulfilled/onRejected回调附加到现有承诺的能力,这与Promise构造函数相当不同。

两者都使用回调只是巧合 - 不是历史上的侥幸,而是对语言功能的适应。

1:理想情况下,你永远不需要这个,因为所有原生异步 API 都会返回 Promise

于 2015-07-09T17:32:17.990 回答
7

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

Promise 构造函数中的resolveandreject参数不是您定义的函数。将它们视为您可以嵌入到异步操作代码中的钩子(通常您resolve具有成功响应和reject失败原因),以便 javascript 最终可以根据异步操作的结果将 Promise 标记为 Fulfilled 或 Rejected ; 一旦发生这种情况,您在其中定义的相应函数将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

于 2018-03-23T16:11:52.573 回答
6

Promise 构造函数 executor 函数的全部意义在于将 resolve 和 reject 函数传播到不使用 Promise 的代码,将其包装并将其转换为使用 Promise。如果您只想将其限制为同步函数,那么是的,可以使用函数的返回值,但这很愚蠢,因为有用的部分是将解析器和拒绝函数传递给稍后实际运行的代码(返回后的方式),例如传递给某些异步 API 的回调。

于 2015-07-09T18:52:10.400 回答
1

下面是 Promise 的执行流程。

var p = new Promise((resolve, reject) =>{
console.log("1");
resolve("OK");
});


//The above code creates a promise and execustion starts immediately.
//it happens aynchronously. So the execution will not be blocked. 
//Promise exustion will not wait for 'then' call on promise

console.log("2");
//The above line displays 2 on the console. 

p.then((result)=>{
console.log("3");
console.log(result);
});

//The above code shoud not block execution. So it may print 4 first 
// then 3
console.log("4");

于 2021-09-03T14:42:28.030 回答