我看到了这个链接:在JavaScript中实现互斥。
另一方面,我读到说JavaScript中没有线程,但这到底意味着什么?
当事件发生时,它们会在代码的哪里中断?
如果JS中没有线程,那么我需要在JS中使用互斥量吗?
具体而言,我想知道使用由setTimeout()
和XmlHttpRequest
的onreadystatechange
调用的函数对全局可访问变量的影响。
我看到了这个链接:在JavaScript中实现互斥。
另一方面,我读到说JavaScript中没有线程,但这到底意味着什么?
当事件发生时,它们会在代码的哪里中断?
如果JS中没有线程,那么我需要在JS中使用互斥量吗?
具体而言,我想知道使用由setTimeout()
和XmlHttpRequest
的onreadystatechange
调用的函数对全局可访问变量的影响。
Javascript被定义为是一种可重入的语言,这意味着用户无需暴露线程,但在实现中可能会存在线程。像setTimeout()
和异步回调函数需要等待脚本引擎休眠后才能运行。
也就是说,在事件中发生的所有事情都必须在下一个事件被处理之前完成。
话虽如此,如果您的代码执行某些操作,希望在异步事件触发时进行值不变,则可能需要使用互斥锁。
例如,如果您有一个数据结构,其中您点击一个按钮并发送XmlHttpRequest,该请求调用一个回调函数以破坏性方式更改数据结构,而您另外还有一个按钮直接更改同一数据结构,则当事件触发时和回调被执行时之间用户可以单击并更新数据结构,然后回调将丢失该值。
虽然您可以创建这样的竞争条件,但非常容易在代码中防止它,因为每个函数都是原子的。实际上,要创建竞争条件需要很多工作和一些奇怪的编码模式。
是的,在访问在不同标签页/窗口之间共享的资源(如 localStorage)时,JavaScript 中可能需要使用互斥锁。
例如,如果用户打开了两个标签页,则以下简单代码是不安全的:
function appendToList(item) {
var list = localStorage["myKey"];
if (list) {
list += "," + item;
}
else {
list = item;
}
localStorage["myKey"] = list;
}
在localStorage项目被“获取”(访问器)和“设置”(变异器)之间的时间内,另一个标签可能已经修改了该值。这通常是不太可能的,但有可能 - 您需要自己判断在特定情况下任何争用所涉及的可能性和风险。
请参阅以下文章以获取更详细信息:
正如@william所指出的那样,如果您的代码执行某些操作,并且期望在异步事件被触发和回调被调用之间值不会改变,则可能需要互斥锁。
更进一步地,如果您的代码执行某些操作,并且期望在异步请求解决之前独占控制资源,则可能需要互斥锁。
一个简单的例子是,当您有一个按钮时,点击该按钮会触发一个ajax调用来在后端创建一个记录。您可能需要一些代码来保护您免受用户过度点击而创建多个记录。有许多方法可以解决这个问题(例如禁用按钮,在ajax成功后启用)。您还可以使用一个简单的锁:
var save_lock = false;
$('#save_button').click(function(){
if(!save_lock){
//lock
save_lock=true;
$.ajax({
success:function()
//unlock
save_lock = false;
}
});
}
}
我不确定这是否是最佳方法,我很想看看其他人如何在javascript中处理互斥,但据我所知,这是一个简单的互斥锁,非常方便。
while
与setTimeout
或者setInterval
中,失败n次后需要用到clearInterval
的重试和超时逻辑。如果保持不变,你只能绕过已加锁的代码。互斥体和共享对象的外部处理与实现本身同样重要。 - MrMeseesif(!save_lock)
和写操作save_lock=true
不是单个原子操作,那么多个线程将能够运行该块。需要一个“测试和设置”IMHO。 - xdhmooreJavaScript是单线程的......虽然Chrome可能是一个新的生物(我认为它也是单线程的,但每个标签页都有自己的JavaScript线程......我没有详细研究过,所以不要引用我)。
然而,你需要担心的一件事是你的JavaScript如何处理多个ajax请求返回的顺序不同。因此,你真正需要担心的只是确保你的ajax调用以一种方式处理,即如果结果与你发送的顺序不同,它们不会互相干扰。
这也适用于超时......
当JavaScript变成多线程时,再考虑互斥锁等问题....
事件被触发,但 JavaScript 执行仍是单线程的。
我的理解是当事件触发时,引擎会停止当前的执行过程以运行事件处理程序。处理程序完成后,脚本执行将恢复。如果事件处理程序更改了某些共享变量,则恢复的代码将看到这些变化“突然出现”。
如果您想要“保护”共享数据,简单的布尔标志就足够了。