本机JavaScript承诺如何处理阻止代码

时间:2015-03-04 14:06:28

标签: javascript concurrency promise

(发布此帖时的第一个障碍是决定一个好的头衔 - 希望我对此做得很好。)

我对本机JavaScript Promise对象的行为(在Windows 7中的Chrome和Firefox中测试)以及它们是否实际并行执行感到有些困惑。我在这里寻求启示,但到现在还没有找到。

考虑这段代码:

(function PromiseTester() {
    var counter = 0;
    new Promise(function(resolve) {
        for(var i = 0; i < 500000000; i++)
            counter = i;

        resolve();
    }).then(function() {console.log('a: ' + counter)});

    new Promise(function(resolve) {
        resolve();
    }).then(function() {console.log('b: ' + counter)});

    console.log('When is this?');
})();

如何向控制台解释以下输出?

  

这是什么时候?
  a:499999999
  b:499999999

虽然创建Promise本身并不是一个阻塞操作,但第一个阻塞循环有效地阻碍了第二个阻塞操作首先解析。

我还尝试将Promise个对象放入数组中,并使用Promise.race()对其进行测试。似乎then() race()的{​​{1}}方法中的代码在第一个Promise中的循环完成后才会执行。

也许这一切都是清醒和花花公子,但我并不完全了解这一切。 Promise对象不应该并行执行和解析吗?

我非常有必要尝试澄清这种情况,以及如何正确地使用Promise进行并行执行。

(请注意,这个问题不是关于PromisePromise.resolve()等问题,而是关于JavaScript Promise.all()的并行(或可能不是并行)性质。)

<小时/> 编辑:在我的一些评论中,我说我有上述相同的问题,即使用异步替换循环也是如此。这是错误的,只是为了避免任何歧义,这是一个例子:

Promise

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Promise Tester</title> </head> <body> <p>Check the console!</p> <script type="text/javascript"> (function Main() { var urls = [ 'Pages/SlowPage.aspx', 'Pages/Page1.html', 'Pages/SlowerPage.aspx', 'Pages/Page2.html' ]; var promises = []; for (var i = 0; i < urls.length; i++) { (function AddPromise(url) { promises.push( new Promise(function (resolve) { var request = new XMLHttpRequest(); request.onload = function () { resolve(url); }; request.open('GET', url, true); request.send(); }) .then(function (result) { console.log('Resolved ' + url + '.'); }) ); })(urls[i]) } Promise .race(promises) .then(function () { console.log('First promise resolved.'); }); Promise .all(promises) .then(function () { console.log('All promises resolved.'); }); })(); </script> </body> </html> 页面只是简单的HTML页面,但在html页面中,我放了一些服务器端aspx代码,使它们“慢”。虽然可能不是百分百绝对防弹,但它应该为此测试环境提供足够的测试解决方案,并且控制台的输出如下:

  

已解决的页数/ Page1.html   已解决的Pages / Page2.html。
  第一个承诺得到解决   已解决的页面/ SlowPage.aspx。
  已解决的页面/ SlowerPage.aspx。
  所有承诺都得到了解决。

在我最初的问题中,我认为“这是什么时候?”这句话令人困惑。在任何Thread.Sleep()对象已解决之前已记录。同样,我认为Promise页面始终(总是?)在html意识到至少有一个Promise.race被解析之前就已解决,这有些出乎意料。如果有人愿意进一步阐述我有兴趣听到的内容,但如果不是,我现在对“这就是它的原因”的结论感到满意。

编辑:在上述所有情况中,我的意思是“并发”而不是“并行”。

1 个答案:

答案 0 :(得分:3)

啊,事件循环和多线程之间的混淆......

当您实例化您的第一个承诺时,底层实现是这样的:在创建之后,JavaScript将控制权移交给下一条指令,即启动循环。此指令(如果您愿意,承诺中的function IETF)开始运行,并且不会停止,直到循环运行完整路线。在任何时候都没有办法让事件循环注意到你的循环已经部分完成了#34;但是,在下一次迭代之前,可以先进行几次操作。

当循环结束时,承诺被标记为已完成,事件循环决定按顺序选择下一个 - 您的第二个承诺!

如果您想在不调用网络工作者或切换语言的情况下以另一种方式执行此操作,而且性能成本很高,您可以process.nextTick()(或者,因为您已经在浏览器中{,} {1}})循环的每次迭代,以便看到我所说的是正确的。然后,您将看到承诺#2正在完成,因为循环的每次迭代都被&#34;交回&#34;到事件循环。

实际上,在您期望JS是多线程的情况下,它只是事件驱动的。意义上的差异具有巨大意义。