我经常读到你不必担心javascript中的竞争条件,因为它是单线程的。但我认为这是因为事件循环的Run-to-completion性质。如果Javascrit没有" Run-to-completion"它可能仍会出现并发问题。特征
让我们考虑一下这段代码:
pending
假设javascript中没有这样的功能" Run-to-completion"并且任何事件都可以被抢占以运行另一个事件/代码。
现在假设第7行被执行并且突然事件被抢先处理第3行的事件。执行第3行& 4,前一个事件从第8行恢复。现在当第8行被执行时,processValues
中新添加的值将丢失,因为pending
函数既没有处理它也没有#39} ; s在{{1}}数组中。
即使是单线程,也会出现竞争状况。那么,说javascript没有竞争条件是不对的,因为它是单线程的?具体来说,这是因为javascript的Run-to-completion功能?
修改
显然,javascript中可能存在竞争条件。我所指的是由于javascript的单线程(或因为Run-to-completion?)性质而不会发生的某种竞争条件。例如,我上面描述的那个。
答案 0 :(得分:2)
是的,我们在单线程JavaScript中有竞争条件。只是没有多线程代码那么多(如果您不使用VS2010
或alert
,请参阅下文)。
您已经开始说“假设没有运行完成功能”,然后描述了依赖于此的竞争条件。但是,这种竞争条件不会发生,因为正如你所说,JavaScript已经完成了。
虽然我们不需要担心JavaScript中存在一类竞争条件,但仍有很多我们做需要担心的事情。例如,异步代码将始终具有竞争条件的潜力。 (这是ajax调用,来自web worker的消息等)
这是一个你常见的错误的例子,这是一个现实世界的竞争条件:
confirm
那是安全的,对吗? 错误。仅仅因为 JavaScript 运行单线程,并不意味着浏览器是单线程的。当浏览器看到var img = document.createElement('img');
img.src = "kittens.png";
img.onload = function() {
console.log("It loaded");
};
document.body.appendChild(img);
时,如果图像位于缓存中,则完全有权在img.src = "kittens.png";
上触发load
事件:该事件将查找任何处理程序,而不是查找任何,所以在当前代码完成后不排队任何回调 - 我们没有看到“已加载”消息。
虽然这是一个基于浏览器的示例,但它是一个通用主体的示例:仅仅因为主机环境运行单个主要JavaScript线程,这并不意味着主机环境不是'多线程,多线程可能对我们的单线程代码产生影响。
这只是一个例子。但确实,我们对其他人是安全的。例如,如果我们更改上面的代码:
img
...我们知道 var img = document.createElement('img');
img.onload = function() {
console.log("It loaded");
};
img.src = "kittens.png";
document.body.appendChild(img);
doSomethingElse();
将在doSomethingElse
运行之前被调用,除非在某些浏览器上遇到一些令人不快的边缘情况(我在看着你,Mozilla) "It loaded"
和alert
函数; bobince covers those in this other answer。 (TL; DR - 至少某些版本的Firefox会在等待用户解除confirm
时触发ajax完成回调。)