112

我看过这个链接:在 JavaScript 中实现互斥。另一方面,我读到 javascript 中没有线程,但这到底是什么意思?

当事件发生时,它们可以在代码中的什么位置中断?

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

具体来说,我想知道使用setTimeout()and调用XmlHttpRequest的函数onreadystatechange对全局可访问变量的影响。

4

7 回答 7

111

Javascript被定义为可重入语言,这意味着没有线程暴露给用户,实现中可能存在线程。诸如异步回调之类的函数setTimeout()需要等待脚本引擎休眠才能运行。

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

话虽如此,如果您的代码在执行某些操作时期望值在触发异步事件和调用回调之间不发生变化,则您可能需要互斥锁。

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

虽然您可以创建这样的竞争条件,但很容易在您的代码中防止这种情况发生,因为每个函数都是原子的。实际上,这将是大量工作并且需要一些奇怪的编码模式来创建竞争条件。

于 2008-09-24T01:04:31.787 回答
22

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

关于 web-workers 的文章:
使用 webworkers 的 javascript 中的多线程
Mozilla on webworkers

这清楚地表明通过 web-workers 的 javascript 具有多线程功能。关于这个问题是javascript中需要互斥锁吗?我不确定这一点。但是这个stackoverflow帖子似乎相关:
N Asynchronous Threads的互斥

于 2011-02-22T14:21:08.007 回答
8

正如@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 中的互斥,但据我所知,这是一个简单的互斥锁,而且很方便。

于 2011-07-20T09:53:40.520 回答
7

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

例如,如果用户打开了两个选项卡,如下所示的简单代码是不安全的:

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

在 localStorage 项目“获取”和“设置”之间,另一个选项卡可能已经修改了该值。这通常不太可能,但可能 - 您需要自己判断与您的特定情况下的任何争用相关的可能性和风险。

有关更多详细信息,请参阅以下文章:

于 2018-02-08T17:35:31.217 回答
3

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

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

这也适用于超时......

当 JavaScript 发展多线程时,可能会担心互斥锁之类的......

于 2008-09-24T00:55:41.947 回答
2

JavaScript语言可以是多线程的,但 javascript 引擎的浏览器嵌入一次只运行一个回调(onload、onfocus、<script> 等)(大概是每个选项卡)。William 关于在注册和接收回调之间使用 Mutex 进行更改的建议不应因此而过于字面意思,因为您不希望阻止干预回调,因为将解锁它的回调将被阻止在当前回调后面!(哇,谈论线程的英语糟透了。)在这种情况下,如果设置了标志,您可能想要按照重新调度当前事件的方式做一些事情,无论是字面意思还是使用 setTimeout() 之类的方法。

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

对不起文字墙!

于 2008-11-28T05:47:00.070 回答
-1

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

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

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

于 2008-09-24T01:04:33.800 回答