承诺是异步还是同步解决?

时间:2016-07-06 14:46:07

标签: javascript angularjs asynchronous promise

我最近一直在使用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();
}

当我写这个逻辑时,我突然意识到,如果两个承诺同时解决(因为它们访问共享资源),可能存在潜在的竞争条件。在考虑了这一点之后,我意识到在{post}返回后then(..)分辨率正在执行,这意味着此代码在JavaScript的同步执行环境中运行。

如果两个combinedArray.concat(arr);声明同时解决,两位combinedArray声明是否可能导致问题,请有人清楚说明一下吗?

[编辑] 我只想添加一些评论,我不介意将数组连接到first的顺序。

3 个答案:

答案 0 :(得分:3)

JavaScript是单线程的,即使在运行异步调用时也会阻止竞争条件。

有些情况下JS会在后台使用另一个线程,比如节点的I / O函数,而web worker API允许你生成一个孤立但独立的线程(没有内存访问但是它们可以传递消息)。

因为JS最初是单线程的,并且运行时中的所有内容都依赖于它(并且旧代码假设它),因此它们不能只添加多线程和潜在的竞争条件。它会破坏一切。因此,此代码将始终正确且安全地工作,因为承诺将被添加到单个队列中并逐个解析。

即使在Web worker(和等效节点)中,每个“线程”都有一个独立的内存空间,不能直接访问另一个线程的变量。 Web工作者专门使用postMessage method来序列化对象并以安全的方式将它们发送到另一个线程。

答案 1 :(得分:1)

有关传递给Promise API的函数的知识:

  • 传递给Promise执行者(fn)的函数new Promise(fn)会立即执行。

  • 传递给处理程序(fn)的函数.then(fn)是异步执行的。

除非您使用Web Workers(感谢@zzzzBov),否则在JavaScript环境中不会同时执行两个函数。无论哪种方式,这不是异步的意思或暗示。

您的示例中没有竞争条件,因为竞争条件决定了实现的问题。因此,虽然您无法预测哪个函数将在另一个函数之前执行,但这两个函数都不会对程序的运行产生负面影响。当然,除非您的程序首先依赖于其中一个连接操作...(我可以看到它不是来自您的编辑)。

"Race condition" Wikipedia

  

竞争条件或竞赛危险是电子,软件或其他系统的行为,其输出取决于其他不可控事件的顺序或时间。 当事件没有按照程序员的意图发生时,它就会成为一个错误。

答案 2 :(得分:0)

我认为已经解释过,您的用户级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
});

这不仅会告诉您何时完成所有异步操作并为您提供组合结果,但它们是有序的,并且会从任一操作传播错误。