Promise 构造函数回调是异步执行的吗?

Posted

技术标签:

【中文标题】Promise 构造函数回调是异步执行的吗?【英文标题】:Is the Promise constructor callback executed asynchronously? 【发布时间】:2015-07-09 21:12:46 【问题描述】:

假设我有这个代码

function y(resolve, reject)

  console.log("Result");
  resolve();
  

var promise = new Promise(y);

我想知道的是函数y是否会异步执行。

【问题讨论】:

没有。 y() 将同步执行。在y() 中,对setTimeout()、AJAX 请求或类似的调用将导致resolve()reject() 被异步执行,但在您发布的代码中并非如此。 因为 Promise 组合良好,并为该行为提供了统一的抽象。否则你只会得到回调汤。仅仅因为组件的行为很简单并不意味着您不需要该组件。例如,Array.forEach 很可能只是一个标准 for 循环。但是Array.forEach 看起来更好,并且允许用户不用担心 for 循环的实现来使用它。 Promise 允许你写 Promise(x).then(y).then(z) 而不是 x(function()y(function()z())) 就是这样。它不会改变 javascript 的基本工作方式 它只是改变了代码的外观。而已。但请记住,易于推理的代码也更易于调试,因此代码的外观并非不重要 当你想组合异步操作时,promise 的好处就很明显了。如果不使用帮助程序库(例如async),就很难等待一组异步回调。 Promise 还使您能够以几乎与同步代码相同的方式编写异步代码(在 ES6 中使用yield,我们将更接近这一点)。 【参考方案1】:

这取决于promise的实现。如果我们检查the spec。你可以找到最终的规范here - 因为这个答案最初是写的,所以它已经完成了。

这里是相关摘录(可以找到原文出处here)

    让完成为 Call(executor, undefined, «resolvingFunctions.[[Resolve]], resolveFunctions.[[Reject]]»)。 如果完成是突然完成,则 让状态为 Call(resolvingFunctions.[[Reject]], undefined, «completion.[[value]]»)。 ReturnIfAbrupt(状态)。

ES6 标准表明承诺的实现是总是异步的(参见第 25.4.5.3 节,Promise.prototype.then 和随附的第 25.4.5.3.1 节,PerformPromiseThen)。我把相关材料放在下面了。

执行承诺然后

    否则,如果 Promise 的 [[PromiseState]] 内部槽的值“已完成”, 让 value 为 promise 的 [[PromiseResult]] 内部槽的值。 执行 EnqueueJob("PromiseJobs", PromiseReactionJob, «fulfillReaction, value»)。 否则,如果 Promise 的 [[PromiseState]] 内部槽的值为“rejected”, 让 reason 为 promise 的 [[PromiseResult]] 内部槽的值。 执行 EnqueueJob("PromiseJobs", PromiseReactionJob, «rejectReaction, reason»)。

TLDR:传递给promise的函数是同步执行的,但后续的then调用总是异步执行的。

【讨论】:

mozilla 版本更容易阅读,因为官方版本是 PDF 格式 我会保留它以防万一,可能会有一些差异,尤其是对未来的读者而言(尽管规范在最终草案中,所以不太可能) 将来,这个答案会过时且无关紧要(我应该知道,我有很多 js 答案从很久以前就这样了):D 希望不是这样。:P 我已将最终的规范草案放入其中,有一个差异,但相当小。 没有官方规范,因为它是草稿。相信我,这不会改变。【参考方案2】:

另一个答案证明这一点,但让我谈谈推理:

Promise 构造函数

promise 构造函数回调(在 ES6 规范或构造函数规范库实现中指定)将始终同步执行 - 这是为了在需要时从中提取延迟(旧形式的 Promise 构造)访问resolve 回调:

var r;
var p new Promise(function(resolve, reject)
    r = resolve;
);
// use r here, for example
arr.push(r);

then 回调

then 将始终异步执行,几乎所有主流的 Promise 实现(Native、bluebird、$q、Q、when、rsvp、promise、jQuery(截至 3.0)等)以及原生 Promise 都实现(或实现具有更多约束的超集)Promises/A+。

正是 Promises/A+ 是由 Promises/A 创建的原因。异步保证将被保留,Zalgo 不会被释放。 (另见this post)。

发生这种情况(异步保证)是完全有意,并且主动防止了竞争条件then 内外的代码将始终以相同的顺序执行。

以下是相关引述:

在执行上下文堆栈仅包含平台代码之前,不得调用onFulfilledonRejected。 [3.1]。

【讨论】:

以上是关于Promise 构造函数回调是异步执行的吗?的主要内容,如果未能解决你的问题,请参考以下文章

promise详解

Promise

手动实现promise源码

es6 Promise

ES6中Promise的简单理解

ES6中Promise的简单理解