5

给定以下测试代码:

var p = new Promise(function(resolve, reject) {
    for(var i=0;i<10000000;++i)
        for(var y=i;y<10000000;++y)
            z = i + y;
    resolve();
});
p.then(function(){alert("resolved");});

此代码应该异步运行,但它会阻止与页面的所有交互。为什么?

这是在 Chrome 44 中测试的,根据这个表Promises 应该被完全实现。

在这里小提琴(警告:阻止标签)

4

2 回答 2

8

此代码应异步运行

是也不是,这取决于您所谈论的代码的哪一部分。您的承诺执行程序(您传入的函数new Promise)中的代码不是异步运行的。从§25.4.3.1,第 10 步:

让完成为 Call(executor, undefined, «resolvingFunctions.[[Resolve]], resolveFunctions.[[Reject]]»)。

new Promise请注意,异步调用执行程序没有任何意义。(这是一个“ Call ”而不是“ EnqueueJob ”。)

异步保证适用于then,而不是new Promise。(§25.4.5.3§25.4.5.3.1。)保证是即使承诺已经解决,您的回调也不会与调用同步then调用,因为它将通过“ EnqueueJob ”调度.

因此,您的代码中发生的是:

  1. 你调用,它同步new Promise调用你的执行器。

  2. 最终 executor 返回并new Promise完成,给我们p.

  3. 你打电话p.then(...);呼叫将作业排队以调用您的回调并立即返回。

  4. JavaScript 作业队列中的当前作业运行完成。

  5. 调用回调的作业被执行,调用回调。

于 2015-05-22T08:07:22.050 回答
2

异步 != 并行

JavaScript 是基于事件的单线程的。承诺不会让你逃脱。只有内置的浏览器功能才能真正并行执行。

因此,在 JavaScript 中,当我们说finp.then(f)异步调用时,它只是意味着稍后在同一个线程中,即在与我们现在所在的任务不同的后续运行到完成任务中。这是一件好事,这就是为什么您不需要使用互斥锁(没有来自并发访问的数据竞争)来锁定事物的原因。

这种对 JS 的混淆似乎很普遍,以至于规范正在改变他们的语言以使这种区别更加清晰。

话虽如此,关于仅浏览器功能并行运行的部分不再完全正确。要真正在 JavaScript 中并行运行密集计算,请查看 web workers,这是一个新的隔离良好的启动线程的概念,它可能会在与您不同的选项卡中运行,除非您可以通过消息与它们交谈。由于它们不与您共享数据空间,因此它们不会破坏 JavaScript 线程保证(或更改我在这里所说的任何内容)。

承诺

Promise 的重点不是提供并发访问,而是解决回调的后向性,使代码更易于推理,也许更重要的是,通过异步操作链解决错误传播(无论它们是否并行运行) .

Promise 还使得一次启动和等待多个异步操作(使用Promise.alland Promise.race)变得微不足道,这对于正确处理(没有错误)和仅通过回调进行推理非常复杂。

于 2015-05-22T13:51:12.257 回答