如何在 JavaScript 中实现锁

     2023-02-16     32

关键词:

【中文标题】如何在 JavaScript 中实现锁【英文标题】:How to implement a lock in JavaScript 【发布时间】:2011-07-17 19:55:47 【问题描述】:

如何在 JavaScript 中实现与 C# 中的 lock 等效的东西?

所以,为了解释我的想法,一个简单的用例是:

用户点击按钮BB 引发 onclick 事件。如果Bevent-state 中,则事件在传播之前等待Bready-state 中。如果Bready-state 中,B 被锁定并设置为event-state,则事件传播。事件传播完成后,B 设置为 ready-state

我可以看到如何完成类似的事情,只需从按钮中添加和删除类ready-state。但是,问题是用户连续两次单击按钮的速度比设置变量的速度要快,因此这种锁定尝试在某些情况下会失败。

有谁知道如何在 JavaScript 中实现一个不会失败的锁?

【问题讨论】:

将不胜感激考虑并行 JS 执行(即像在 IE9 中)的答案。 @smart 所以你想暂时暂停当前的事件传播,直到前一个事件的传播完成。我不认为那可以做到。您可以这样做:丢弃该事件,然后在前一个事件完成传播时触发另一个事件。 @OrangeDog - 我只听说 IE9 尝试使用专用内核进行编译,没有关于并行执行,你能引用一个来源吗? @Brandon - 正如您所建议的,这可能意味着与渲染器平行,而不是与自身平行。 相关:***.com/questions/6266868/… 【参考方案1】:

锁在 JS 中是一个有问题的想法,它旨在实现无线程且不需要并发保护。您希望合并对延迟执行的调用。我遵循的模式是使用回调。像这样的:

var functionLock = false;
var functionCallbacks = [];
var lockingFunction = function (callback) 
    if (functionLock) 
        functionCallbacks.push(callback);
     else 
        $.longRunning(function(response) 
             while(functionCallbacks.length)
                 var thisCallback = functionCallbacks.pop();
                 thisCallback(response);
             
        );
    

您也可以使用 DOM 事件侦听器或 pubsub 解决方案来实现这一点。

【讨论】:

能否请您提供参考文档来证明您的声明“JS 旨在实现无线程且不需要并发保护”?我想了解更多相关信息。 +1 - 鉴于 Node.js(JavaScript Web 服务器)是为利用 JavaScript 的单线程和回调机制而构建的,我同意您不必担心锁定属性将没有竞争条件。 $.longRunning 来自哪个库?它不在(当前)jQuery 中。 什么时候设置functionLock? “旨在实现无线程且不需要并发的 JS”是可疑的。 JS 不使用抢占式并发,但允许您使用协作并发(基于回调或异步/等待)。在使用这些时,您肯定会遇到竞争条件,并且可能希望使用互斥抽象来避免它们。【参考方案2】:

JavaScript 与 exceptions(在某些版本的 Firefox 中为 XMLHttpRequest onreadystatechange 处理程序)event-loop concurrent 是一样的。所以在这种情况下你不必担心锁定。

JavaScript 有一个基于“事件循环”的并发模型。该模型与 C 或 Java 等其他语言中的模型完全不同。

...

JavaScript 运行时包含一个消息队列,它是要处理的消息列表。每条消息都关联一个功能。当堆栈为空时,从队列中取出一条消息并进行处理。 处理包括调用相关函数(并因此创建一个初始堆栈帧)。当堆栈再次变空时,消息处理结束。

...

每条消息都在处理任何其他消息之前被完全处理。这在推理您的程序时提供了一些很好的属性,包括这样一个事实:每当一个函数运行时,它不能被抢占并且会在任何其他代码运行之前完全运行(并且可以修改函数操作的数据)。 这与 C 不同,例如,如果一个函数在一个线程中运行,它可以随时停止以在另一个线程中运行其他代码。

此模型的一个缺点是,如果一条消息需要很长时间才能完成,Web 应用程序将无法处理用户交互,例如单击或滚动。浏览器通过“脚本运行时间过长”对话框来缓解这种情况。 一个好的做法是缩短消息处理时间,并在可能的情况下将一条消息缩减为多条消息。

有关事件循环并发的更多链接,请参阅E

【讨论】:

并且在javascript中使用Web Workers(non UI threads),每个对象clones在发送到另一个工作线程(线程)或UI线程之前,然后对象在不同的​​线程中有不同的实例,每个线程都有自己的事件循环,最后我同意迈克的回答作为一个有用的答案。谢谢迈克。【参考方案3】:

我已经成功了mutex-promise。

我同意您可能不需要锁定您的情况的其他答案。但是,永远不需要锁定 Javascript 是不正确的。在访问不处理并发的外部资源时,您需要互斥。

【讨论】:

感谢非常需要的东西。【参考方案4】:

锁是多线程系统所需的概念。即使使用工作线程,消息也是在工作线程之间按值发送的,因此不需要锁定。

我怀疑您只需要在按钮之间设置一个信号量(标记系统)。

【讨论】:

你有任何用 JavaScript 实现的“信号量/标记系统”的示例或资源吗? PLenty 就在这里,即***.com/questions/4194346/… James 我在您发布的链接中没有看到任何信号量示例。我需要阻止对外部服务器的调用,因为它们每秒只允许一个请求,所以我需要一个标记示例来阻止调用,直到我的 for next 循环内经过的时间过去,而不跳过每个循环的请求。 嗨@克劳斯。有两件事浮现在脑海中,根据您的堆栈,您可以只使用像 Axios 这样的库,它似乎支持速率限制插件,或者您可以创建一个基于域的速率限制请求的网络工作者。 感谢您的回复。我通过在处理结束时结合 setInterval 调用 click 事件来解决它。将间隔设置为 1000 毫秒我现在遵守主机服务器对请求的限制,并且在返回响应之前它不再退出 Ajax 调用。【参考方案5】:

为什么不禁用按钮并在完成事件后启用它?

<input type="button" id="xx" onclick="checkEnableSubmit('true');yourFunction();">

<script type="text/javascript">

function checkEnableSubmit(status)   
  document.getElementById("xx").disabled = status;


function yourFunction()

//add your functionality

checkEnableSubmit('false');


</script>

编码愉快!!!

【讨论】:

【参考方案6】:

根据我的情况,对 JoshRiver 的回答有所补充;

var functionCallbacks = [];
    var functionLock = false;
    var getData = function (url, callback) 
                   if (functionLock) 
                        functionCallbacks.push(callback);
                    else 
                       functionLock = true;
                       functionCallbacks.push(callback);
                        $.getJSON(url, function (data) 
                            while (functionCallbacks.length) 
                                var thisCallback = functionCallbacks.pop();
                                thisCallback(data);
                            
                            functionLock = false;
                        );
                    
                ;

// Usage
getData("api/orders",function(data)
    barChart(data);
);
getData("api/orders",function(data)
  lineChart(data);
);

只有一个 api 调用,这两个函数将消耗相同的结果。

【讨论】:

【参考方案7】:

锁在 JS 中仍然有用。根据我的经验,我只需要使用锁来防止垃圾邮件点击进行 AJAX 调用的元素。 如果您为 AJAX 调用设置了加载程序,那么这不是必需的(以及在单击后禁用按钮)。 但无论哪种方式都是我用于锁定的方式:

var LOCK_INDEX = [];
function LockCallback(key, action, manual) 
    if (LOCK_INDEX[key])
        return;
    LOCK_INDEX[key] = true;
    action(function ()  delete LOCK_INDEX[key] );
    if (!manual)
        delete LOCK_INDEX[key];

用法:

手动解锁(通常用于 XHR)

LockCallback('someKey',(delCallback) =>  
    //do stuff
    delCallback(); //Unlock method
, true)

自动解锁

LockCallback('someKey',() =>  
    //do stuff
)

【讨论】:

【参考方案8】:

这是一个简单的锁机制,通过闭包实现

const createLock = () => 

    let lockStatus = false

    const release = () => 
        lockStatus = false
    

    const acuire = () => 
        if (lockStatus == true)
            return false
        lockStatus = true
        return true
    
    
    return 
        lockStatus: lockStatus, 
        acuire: acuire,
        release: release,
    


lock = createLock() // create a lock
lock.acuire() // acuired a lock

if (lock.acuire())
  console.log("Was able to acuire");
 else 
  console.log("Was not to acuire"); // This will execute


lock.release() // now the lock is released

if(lock.acuire())
  console.log("Was able to acuire"); // This will execute
 else 
  console.log("Was not to acuire"); 


lock.release() // Hey don't forget to release

【讨论】:

如何在 Wordpress 中实现 javascript

】如何在Wordpress中实现javascript【英文标题】:HowtoimplementjavascriptintoWordpress【发布时间】:2015-04-0915:44:20【问题描述】:我在理解如何将javascript放入wordpress主题时遇到了一些麻烦。我知道我必须保存这个javascript:http://ajax.googleap... 查看详情

如何在javascript中实现区域/代码折叠

】如何在javascript中实现区域/代码折叠【英文标题】:howtoimplementregions/codecollapseinjavascript【发布时间】:2010-12-2715:45:11【问题描述】:如何在VisualStudio中为JavaScript实现区域(也称为代码折叠)?如果javascript中有数百行,那么在v... 查看详情

如何在 javascript 中实现 Random.nextDouble()?

】如何在javascript中实现Random.nextDouble()?【英文标题】:HowtoimplementRandom.nextDouble()injavascript?【发布时间】:2019-02-2721:36:57【问题描述】:我正在使用Math.floor((Math.random()*max-min)+min)生成随机数,这个函数和random.nextDouble()有什么区... 查看详情

如何在javascript中实现分层多级数据表?

】如何在javascript中实现分层多级数据表?【英文标题】:HowtoimplementhierarchicalmultileveldatatableinjavaScript?【发布时间】:2019-02-0123:40:40【问题描述】:我在不使用任何插件或库的情况下实现多级数据表。我想基于javaScript、JQuery或ang... 查看详情

如何在 JavaScript/jQuery 中实现重载?

】如何在JavaScript/jQuery中实现重载?【英文标题】:HowcanimplementoverloadinginJavaScript/jQuery?【发布时间】:2011-09-2119:19:36【问题描述】:我正在尝试调用具有相同签名的函数。示例:有两个同名函数:<script>varobj1,obj2,obj3,obj4,obj5;... 查看详情

如何在 Javascript 中实现安全的 OAuth2 消费?

】如何在Javascript中实现安全的OAuth2消费?【英文标题】:HowdoIimplementsecureOAuth2consumptioninJavascript?【发布时间】:2012-07-1112:40:38【问题描述】:我正在用PHP设计一个将使用OAuth2.0的API。我的最终目标是用javascript(使用AngularJS)构... 查看详情

如何在 Javascript 中实现 Haskell 的 FRP Behavior 类型?

】如何在Javascript中实现Haskell的FRPBehavior类型?【英文标题】:HowtoimplementHaskell\'sFRPBehaviortypeinJavascript?【发布时间】:2017-07-1111:10:15【问题描述】:我想了解Haskell中函数式反应式编程的原意,以及它与FRP在Javascript中的实际应用... 查看详情

如何在 html/javascript 中实现登录弹出窗口

】如何在html/javascript中实现登录弹出窗口【英文标题】:Howtoimplementloginpopupinhtml/javascript【发布时间】:2014-01-0919:43:22【问题描述】:基本上,我想创建一个登录弹出窗口,就像许多路由器必须访问设置页面一样:是否可以在html... 查看详情

如何在javascript中实现<br>? [复制]

】如何在javascript中实现<br>?[复制]【英文标题】:Howtoimplement<br>injavascript?[duplicate]【发布时间】:2020-11-0114:12:33【问题描述】:我对Web开发还很陌生,因此对实现这一点有疑问。varobj=[[name:"John",age:30,city:"NewYork",name:"Ken"... 查看详情

如何在用于编辑 HTML 的 Javascript 组件中实现视图模型分离?

】如何在用于编辑HTML的Javascript组件中实现视图模型分离?【英文标题】:HowcanIachieveview-modelseparationinaJavascriptcomponentforeditingHTML?【发布时间】:2015-09-2600:27:41【问题描述】:我需要为特定的HTML子集构建一个浏览器内WYSI(或多或... 查看详情

如何使用 Javascript 或 ajax 在文本字段中实时注入或添加输入字段的值?

】如何使用Javascript或ajax在文本字段中实时注入或添加输入字段的值?【英文标题】:HowdoIauseJavascriptorajaxtoinjectoraddathevalueofaninputfieldinatextfieldinrealtime?【发布时间】:2016-12-2602:11:10【问题描述】:我有一个id为#image_tag_list_tokens的... 查看详情

javascript此代码段显示了如何在纯javascript中实现面向对象的继承,以便可以继承正确的函数(代码片段)

查看详情

如何在 JavaScript 中实现决策树。寻找比我丑陋的解决方案更好的解决方案[关闭]

】如何在JavaScript中实现决策树。寻找比我丑陋的解决方案更好的解决方案[关闭]【英文标题】:Howtoimplementadecisiontreeinjavascript.Lookingforabettersolutionthanmyuglyones[closed]【发布时间】:2012-01-1205:06:08【问题描述】:我正在寻找一种在jav... 查看详情

如何在javascript中实现多个项目的计数?(代码片段)

我想用Js处理多个项目的计数。1)我想要的是当点击加号或减号时,旁边的计数器数字会更新;2)考虑到通过点击添加房间,另一个房间被添加到列表中,它的标题应该改变,例如在这种情况下是(房间二)。这是我的js代码$("... 查看详情

如何在 javascript/HTML5/NodeJS 中实现客户端-服务器-客户端基础架构的想法

】如何在javascript/HTML5/NodeJS中实现客户端-服务器-客户端基础架构的想法【英文标题】:Ideashowtoimplementaclient-server-clientinfrastructureinjavascript/HTML5/NodeJS【发布时间】:2013-10-3123:42:05【问题描述】:我目前正在开展一个项目,其中基... 查看详情

您如何在您的网站中实施 quickblox?

...初学者。所以,这可能是一个非常愚蠢的问题。我想使用javascript将quickblox包含到我的网站中。到目前为止,我已将javascript包含到我的网站中并创建了quickblox管理端应用程序。您如何在您的网站 查看详情

如何跨 SwiftUI 应用程序跟踪所有触摸

】如何跨SwiftUI应用程序跟踪所有触摸【英文标题】:HowtotrackalltouchesacrossSwiftUIapp【发布时间】:2020-09-1620:25:50【问题描述】:我正在尝试在SwiftUI应用中实现锁屏。我需要跟踪每个事件以重新启动锁定计时器。在UIKit应用程序中... 查看详情

如何在 TypeScript 中实现睡眠功能?

...能。我的用例是在几秒钟后提交表单后重定向用户,这在JavaScript中非常简单,但我不确定如何在TypeScript 查看详情