【发布时间】:2015-03-05 00:55:38
【问题描述】:
(发布此内容时的第一个障碍是决定一个好的标题 - 希望我做得不错。)
我对原生 JavaScript Promise 对象的行为方式(在 Windows 7 的 Chrome 和 Firefox 中测试)以及它们是否实际并行执行感到有些困惑。我在这里寻求关于 SO 的启发,但目前还没有发现。
考虑一下这段代码:
(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?');
})();
如何向控制台解释以下输出?
这是什么时候?
答:499999999
b: 499999999
看起来虽然创建 Promise 本身不是阻塞操作,但第一个中的阻塞循环有效地阻碍了第二个第一个解析。
我还尝试将Promiseobjects 放入一个数组中,并使用Promise.race() 对其进行测试。似乎race()Promise 的then() 方法中的代码在第一个Promise 中的循环完成之前不会执行。
也许这一切都是清醒和花花公子,但我不太明白这一切的意义。 Promise 对象不应该并行执行和解析吗?
我非常有义务澄清这种情况,以及如何正确使用 Promise 进行并行执行。
(请注意,这个问题与 Promise.resolve()、Promise.all() 等无关,而是关于 JavaScript Promise 的并行或非并行性质。)
编辑:在我的一些 cmets 中,我说我遇到了与上述相同的问题,即使用异步替换循环也是如此。这是错误的,为了避免任何歧义,这里有一个例子:
<!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() 代码以使它们“慢”。虽然可能不是 100% 绝对防弹,但它应该为在这种情况下的测试提供足够的解决方案,并且控制台的输出如下:
已解决的页面/Page1.html。
已解决的页面/Page2.html。
第一个承诺已解决。
已解决的页面/SlowPage.aspx.
已解决的页面/SlowerPage.aspx.
所有的承诺都解决了。
在我最初的问题中,我认为“这是什么时候?”这句话令人困惑。在任何Promise 对象解析之前记录。同样,我认为在Promise.race 意识到至少一个Promise 已解决之前,html 页面始终(总是?)解决有点出乎意料。如果有人愿意进一步详细说明,我很想听听,但如果没有,我对“就是这样”的结论暂时感到满意。
编辑:我真正的意思是“并发”而不是“并行”。
【问题讨论】:
-
JavaScript 是按顺序同步执行的。您的代码中没有异步操作。我不知道你为什么会期待不同的结果。
-
JavaScript 是单线程的(除非您使用网络工作者等)。您发布的代码将按照请求的顺序运行,因为您的 Promise 中没有异步工作,它们将按调用的顺序登录。
-
如果我发出异步 AJAX 请求而不是循环,但问题仍然存在。
-
@OskarLindberg 您是在完成 AJAX 请求时调用
resolve(),还是在您触发它之后调用 - 即您是否将调用resolve移动到成功回调或类似的,或者AJAX 请求是否直接替换了您问题中的for循环,而对resolve的调用仍在其后? -
我在完成时解决了。我不应该吗?着手处理响应并解决修改后的结果似乎是个好主意。
标签: javascript concurrency promise