ES6 Promise阻止页面

时间:2015-05-22 08:04:58

标签: javascript ecmascript-6 es6-promise

给出以下测试代码:

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中测试的,根据this table Promises应该完全实现。

Fiddle here(警告:阻止标签页)

2 个答案:

答案 0 :(得分:7)

  

此代码应以异步方式运行

是和否,这取决于您所谈论的代码的哪一部分。您的promise执行者中的代码(传递给new Promise的函数)是异步运行。来自§25.4.3.1,第10步:

  

让完成调用(执行者,未定义,«resolvingFunctions。[[Resolve]],resolvingFunctions。[[Reject]]»)。

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

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

所以你的代码会发生什么:

  1. 您拨打new Promise,同步调用您的执行人

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

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

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

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

答案 1 :(得分:2)

异步!=并行

JavaScript是基于事件和单线程的。承诺不会让你逃避。只有内置的浏览器功能才能实现并行

因此,在JavaScript中,当我们说f中的p.then(f)被称为异步时,它只是意味着以后在同一个线程中,即在随后的完成任务中,与我们现在的任务分开。这是一件好事,这就是为什么你不需要用互斥锁来锁定东西(没有来自并发访问的数据竞争)。

关于JS的这种混淆似乎很常见,规范是changing their language以使这种区别更加清晰。

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

承诺

承诺的重点不是提供并发访问,而是为了解决回调的落后问题并使代码更易于推理,或许更重要的是,通过异步操作链解决错误传播(无论它们是否并行运行)或不)。

Promise也使得一次启动和等待多个异步操作(使用Promise.allPromise.race)变得微不足道,这是一个非常复杂的事情(没有错误)和原因只是回调。