【问题标题】:Is the Promise constructor callback executed asynchronously?Promise 构造函数回调是异步执行的吗?
【发布时间】: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,我们将更接近这一点)。

标签: javascript promise es6-promise


【解决方案1】:

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

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

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

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

执行承诺然后

  1. 否则,如果 Promise 的 [[PromiseState]] 内部槽的值“已完成”,
    • 让 value 为 promise 的 [[PromiseResult]] 内部槽的值。
    • 执行 EnqueueJob("PromiseJobs", PromiseReactionJob, «fulfillReaction, value»)。
  2. 否则,如果 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 内外的代码将始终以相同的顺序执行。

以下是相关引述:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-30
    • 1970-01-01
    • 2014-08-15
    相关资源
    最近更新 更多