本机JavaScript承诺如何处理阻塞代码 [英] How Native JavaScript Promise Handles Blocking Code

查看:50
本文介绍了本机JavaScript承诺如何处理阻塞代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(发布此文章时的第一个障碍是决定一个好标题-希望我能做到这一点。)

(The first obstacle when posting this was deciding on a good title - hope I did OK with that.)

我对本地JavaScript的使用方式有点困惑 Promise 对象的行为(在Windows 7中的Chrome和Firefox中进行了测试)以及它们是否实际上并行执行。我在这里寻求关于SO的启示,但到目前为止还没有找到。

I'm slightly bewildered by how the native JavaScript Promise object behaves (tested in Chrome and Firefox in Windows 7), and whether or not they actually execute in parallel or not. I sought enlightenment here on SO, but found none as of yet.

考虑以下代码块:

(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?');
})();

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

How can I explain the following output to the console?


这是什么时候?

a:499999999

b:499999999

When is this?
a: 499999999
b: 499999999

似乎创建Promises本身并不是一个阻塞操作,但是第一个中的阻塞循环实际上阻碍了第二个对象首先解决。

It would seem that although creating the Promises is not a blocking operation in itself, the blocking loop in the first one effectively hinders the second one from resolving first.

我还尝试将 Promise 对象放入数组中,并使用 Promise.race()。似乎 race() Promise then()方法中的代码直到第一个 Promise 的循环结束后才执行。

I also tried putting the Promiseobjects in an array and test them with Promise.race(). It seems that code in the then() method of the race() Promise does not execute until the loop in the first Promise is finished.

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

Maybe this is all sober and dandy, but I don't quite get what to make of it all. Shouldn't the Promise objects execute and resolve in parallel?

我很想尝试任何尝试弄清情况,以及如何正确使用 Promise 进行并行执行。

I'd be much obliged for any attempts to clarify the situation, and how to use Promise properly for parallel execution.

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

(Please not that this question is not about Promise.resolve(), Promise.all() etc. but about the parallel - or possibly not parallel - nature of a JavaScript Promise.)



编辑:在我的一些评论中,我说过,即使将循环替换为异步内容时,我也遇到与上述相同的问题。这是错误的,只是为了避免歧义,这里有一个示例:


In some of my comments, I said I have the same issue as described above even when replacing the loop with something asynchronous. This was wrong, and just to avoid any ambiguity, here's an example:

<!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 页面中,我放置了一些服务器端 Thread.Sleep()代码来制作它们慢。虽然也许不是百分之百绝对防弹,但它应该为这种情况下的测试提供足够的解决方案,并且控制台的输出如下:

The html pages are just that - plain and simple HTML pages, but in the aspx pages i put some server side Thread.Sleep() code to make them "slow". While perhaps not one-hundred-percent-absolutely-bulletproof, it should provide a sufficient solution for testing in this context, and the output to the console is as follows:


已解决的页面/Page1.html。

已解决的页面/Page2.html。

第一承诺得到解决。

解决Pages / SlowPage.aspx。

已解决Pages / SlowerPage.aspx。

所有承诺均已解决。

Resolved Pages/Page1.html.
Resolved Pages/Page2.html.
First promise resolved.
Resolved Pages/SlowPage.aspx.
Resolved Pages/SlowerPage.aspx.
All promises resolved.

在我最初的问题中,我认为短语这是什么时候?令人困惑。在任何 Promise 对象解决之前之前被记录。同样,我认为 html 页面始终(总是?)在 Promise.race 意识到在至少有一个 Promise 已解决。如果有人愿意进一步阐述这一点,我很想听听,但是如果现在不满意,我的结论是事实就是如此。

In my original question, I thought it was confusing that the phrase "When is this?" was logged before any of the Promise objects resolved. Likewise, I think it's somewhat unexpected that the html pages consistently (always?) resolves before Promise.race realizes that at least one Promise was resolved. If anyone would care to further elaborate on that I'd be interested to hear, but if not I'm satisfied with the conclusion that "that's just how it is", for now.

编辑:在以上所有内容中,我的意思是并发而不是并行。

I really mean "concurrent" rather than "parallel" in all of the above.

推荐答案

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

Ah, the confusion between an event loop and multithreading...

实例化第一个诺言时,其基础实现是在创建之后, JavaScript将控制权移交给下一条指令,即开始循环。该指令(如果愿意,可以使用诺言中的函数 IETF函数),并且不会停止,直到循环运行了整个过程。事件循环绝对不会注意到您的循环已部分完成,但是可以进行一些操作直到下一次迭代。

When you instantiate your first promise, the underlying implementation is such that after the creation, JavaScript hands over control back to the next instruction, which is to start the loop. This instruction (if you prefer, the function IETF in the promise) starts running, and does not stop until the loop has run its full course. At no point is there a way for the event loop to notice that your loop is "partially done" but that it's okay to go and slot in a couple of operations until the next iteration.

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

When the loop is over, the promise is marked as completed, and the event loop decides to pick the next in order - your second promise!

如果想要以另一种方式执行此操作而不需要调用网络工作人员或切换语言,这会付出巨大的性能代价,您可以 process.nextTick()(或者,因为您处于浏览器,每次循环迭代 setTimeout(function(){},0))以便查看我的意思是正确的。然后,您将看到由于循环的每次迭代交还到事件循环而完成了承诺#2。

If you'd like to do it another way without invoking webworkers or switching language, at a huge cost of performance, you could process.nextTick() (or, since you're in a browser, setTimeout(function() {}, 0)) every iteration of your loop in order to see that what I'm saying is correct. You will then see promise #2 being completed due to every iteration of the loop being "handed back" to the event loop.

实际上,您期望JS是多线程的,它只是事件驱动的。概念上的差异具有深远的意义。

In reality, where you are expecting JS to be multithreaded, it is just event-driven. Difference in conception with huge implications.

这篇关于本机JavaScript承诺如何处理阻塞代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆