承诺是否异步或同步解决
Do promises resolve asynchronously or synchronously?
我最近一直在使用 JavaScript 承诺,遇到了以下情况,这让我思考:
var combinedArray = [];
function getArrayOne() {
$http.post(arrayOnePath).then(function(arr) {
combinedArray = combinedArray.concat(arr);
}) // More code preventing me from using Promise.all(...)
}
function getArrayTwo() {
$http.post(arrayTwoPath).then(function(arr) {
combinedArray = combinedArray.concat(arr);
}) // More code preventing me from using Promise.all(...)
}
function getAllArrays() {
getArrayOne();
getArrayTwo();
}
当我编写这个逻辑时,我突然意识到,如果两个承诺同时解决(当它们访问共享资源时),则可能存在潜在的竞争条件。在考虑了一段时间后,我意识到then(..)
决议是在帖子返回后执行的,这意味着这段代码在 JavaScript 的同步执行环境中运行。
有人可以向我澄清一下,如果两个承诺同时解决,这两个combinedArray.concat(arr);
声明是否会引起问题?
[编辑]在评论之后,我只想补充一点,我不介意数组连接成combinedArray
的顺序。
JavaScript 是单线程的,即使在运行异步调用时也能防止竞争情况。
在某些情况下,JS将在后台使用另一个线程,例如节点的I/O函数,并且Web worker API允许您生成一个隔离但独立的线程(没有内存访问,但它们可以传递消息)。
因为JS最初是单线程的,运行时中的所有内容都依赖于此(旧代码假设它),所以他们不能只添加多线程和潜在的竞争条件。它会破坏一切。因此,此代码将始终正确安全地工作,因为承诺将被添加到单个队列中并一个接一个地解析。
即使在 Web Worker 中(以及等效的节点),每个"线程"都有一个隔离的内存空间,并且不能直接从另一个线程访问变量。Web 工作者专门使用 postMessage
方法来序列化对象,并以安全的方式将它们发送到另一个线程。
关于传递到 Promise API 的函数需要了解的事情:
-
传递给承诺执行器 (
new Promise(fn)
) 的函数fn
会立即执行。 -
传递给处理程序(
.then(fn)
)的函数fn
是异步执行的。
在 JavaScript 环境中,没有两个函数会同时执行,除非你使用的是 Web Workers(谢谢@zzzzBov)。无论哪种方式,这都不是异步的含义或暗示。
您的示例中没有争用条件,因为争用条件决定了实现存在问题。因此,尽管您无法预测哪些函数将在另一个函数之前执行,但这两种结果都不会对程序的操作产生不利影响。当然,除非你的程序依赖于首先执行的串联操作之一......(我可以看到它没有,从你的编辑)。
"竞争条件"维基百科:
竞争条件或竞争危险是电子、软件或其他系统的行为,其中输出取决于其他不可控事件的顺序或时间。当事件没有按照程序员预期的顺序发生时,它就会成为一个错误。
正如我已经解释过的,你的用户级Javascript是单线程的(除了webWorkers,这里不涉及)。
没有两个Javascript片段在同一时刻运行,所以你没有竞争条件。 您的特定代码示例确实存在一个问题,不知道何时完成两个异步操作,以便您可以使用结果。 因此,您可以使用如下结构:
function getArrayOne() {
return $http.post(arrayOnePath).then(function(arr) {
// do any processing here on or with arr
return arr;
})
}
function getArrayTwo() {
return $http.post(arrayTwoPath).then(function(arr) {
// do any processing here on or with arr
return arr;
})
}
function getAllArrays() {
return Promise.all(getArrayOne(), getArrayTwo()).then(function(results) {
// results[0] is first array
// results[1] is second array
return results[0].concat(results[1]);
});
}
getAllArrays().then(function(results) {
// all results available
}, function(err) {
// error occurred here in either async operation
});
这不仅会告诉您所有异步操作何时完成并为您提供组合结果,而且它们按顺序排列,并且会传播任一操作的错误。
- 在控制器和数据对象之间同步数据
- 同步调用,直到用户通过angular验证为访问者
- 如何解决Yii中的页面刷新问题
- javascript函数同步
- 测试Angular Service解决错误回调中的promise
- 与运行长作业(javascript,node.js)的第三方API同步的最佳实践
- 如何解决Access Control Allow Origin错误
- 显示具有服务器端自动时间注销的同步倒计时计时器
- 如何将Knockout.JS与服务器已经在DOM中呈现的数据同步
- 音频和动画在javasctipt循环中同步
- 在chrome扩展程序中同步IndexedDB的解决方案
- 使用jsonp解决方法进行同步ajax调用
- 如何同步解决es6承诺链
- 同步解决HTTP延迟承诺
- 需要同步 pouchDB 数据库的解决方案
- 主线程上的同步XMLHttpRequest已弃用..尝试了许多不同的解决方案
- javascript的同步延迟或命令解释器的setTimeout解决方案
- 避免将ajax请求设置为同步的解决方案
- 解决在angular模板中包含脚本标签导致“同步XMLHttpRequest..”的问题;错误感觉很脏
- 承诺是否异步或同步解决