2008-09-24 108 views
87

我已看过此链接:Implementing Mutual Exclusion in JavaScript。 另一方面,我已经阅读了JavaScript中没有线程,但究竟是什么意思?JavaScript中是否需要互斥体?

当事件发生时,代码中哪里可以中断?

如果JS中没有线程,我是否需要在JS中使用互斥锁?

具体而言,我想知道使用函数setTimeout()XmlHttpRequestonreadystatechange对全局访问变量的影响。

+1

不,没有互斥或JavaScript的任何其他并发控制工具。请参阅[为什么没有JavaScript中的并发控制工具](http://uzairfarooq.github.io/why-no-concurrency-control-tool-in-javascript/)。 – 2015-07-17 08:06:19

回答

87

JavaScript是定义为折返语言,这意味着有没有线程暴露给用户,实现中可能有线程。像setTimeout()和异步回调函数需要等待脚本引擎在能够运行之前进入睡眠状态。

这意味着在处理下一个事件之前,事件中发生的所有事情都必须完成。

这就是说,如果你的代码做了一些事情,那么当异步事件被触发和回调被调用时,它的值就不会改变。

例如,如果您有一个数据结构,您可以在其中单击一个按钮并发送调用回调的XmlHttpRequest,以破坏性方式更改数据结构,并且您有另一个按钮可以直接更改同一数据结构当事件被触发并且执行回调时,用户可能在回调之前点击并更新数据结构,然后可能丢失该值。

虽然您可以创建这样的竞争条件,但由于每个函数都是原子的,因此很容易防止在您的代码中出现这种情况。事实上,这将是很多工作,并采取一些奇怪的编码模式来创造竞争条件。

+1

创建这种竞争条件并不难:例如,我在字段中有一个“onkeyup”事件,它会触发对数据库的ajax调用以获取一些值。快速输入数据很容易导致乱序结果。 – thomasb 2017-11-17 16:15:11

5

JavaScript是单线程的......虽然Chrome可能是一个新的野兽(我认为它也是单线程的,但每个标签都有它自己的JavaScript线程......我没有仔细研究它,所以不要在那里引用我的话)。

但是,您需要担心的一件事是您的JavaScript如何处理多个Ajax请求,它们的传递顺序与您发送的顺序不同。所以,你真正需要担心的是确保你的Ajax调用的处理方式,如果结果以不同于你发送的顺序返回,他们将不会踩到对方的脚上。

这同样适用于超时太...

JavaScript时长多线程,那么也许担心互斥等....

1

事件发出信号,但JavaScript执行仍然是单线程的。

我的理解是,当事件发出信号时,引擎会停止正在执行的事件,以运行事件处理程序。处理程序完成后,脚本执行恢复。如果事件处理程序更改了某些共享变量,则恢复代码将会看到这些“出乎意料”的变化。

如果你想“保护”共享数据,简单的布尔标志应该就足够了。

1

JavaScript中,语言,可以为多线程的,只要你想,但JavaScript引擎的浏览器的嵌入一次只运行一个回调(的onload,聚焦状态,<脚本>,等...)(每片,据推测)。威廉关于在注册和接收回调之间使用Mutex的建议不应该因为这个原因而被过分地使用,因为你不想在中间回调中阻塞,因为解锁它的回调将被阻止在当前回调之后! (哇,英语很讨厌线程的问题。)在这种情况下,如果设置了标志,可能需要按照重新分派当前事件的方式执行某些操作,无论是字面上的还是setTimeout()之类的。

如果您使用的是JS的不同嵌入方式,并且一次执行多个线程,它可能会变得更加冒险,但由于JS可以轻松使用回调并将对象锁定在属性访问上,显式锁定是几乎没有必要。但是,如果为使用多线程的通用代码(例如游戏脚本)设计的嵌入也没有给出一些明确的锁定原语,我会感到惊讶。

对不起,对文本的墙!

15

这个问题的答案有点过时,虽然在给定的时候是正确的。如果查看不使用webworkers的客户端JavaScript应用程序,仍然正确。

文章在网络工作人员:
multithreading in javascript using webworkers
Mozilla on webworkers

这清楚地表明,通过网络工作人员的JavaScript具有多线程功能。至于这个问题是JavaScript中需要互斥体?我不确定这一点。但这个计算器后,似乎相关:
Mutual Exclusion for N Asynchronous Threads

+2

从过去爆炸,但当多个标签访问相同的本地存储时,我遇到了互斥锁的需要 – psp 2014-05-15 13:46:10

+1

Web工作人员不会影响重入,因为它们不共享变量状态,只通过传递消息来与主线程通信,这会触发事件。 – Alnitak 2014-08-01 11:05:00

9

由于@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的相互排斥,但据我所知,这是一个简单的互斥和它很方便。

1

是的,当访问在标签页/窗口之间共享的资源时,Javascript中可能需要互斥锁,例如localStorage

例如,如果用户有两个选项卡中打开,像下面这个简单的代码是不安全的:

function appendToList(item) { 
    var list = localStorage["myKey"]; 
    if (list) { 
     list += "," + item; 
    } 
    else { 
     list = item; 
    } 
    localStorage["myKey"] = list; 
} 

的localStorage的项目是“得到”和“设置”之间的时间里,另一个标签可以有修改了这个值。这通常不太可能,但可能 - 您需要自己判断在特定情况下与任何争用相关的可能性和风险。

见一个更详细的在下面的文章: