如何在JavaScript中实现与C#中的lock
相当的东西?
所以,为了解释我在想什么,一个简单的用例是:
用户点击按钮B
。 B
提出了onclick事件。如果B
位于event-state
,则会在传播前等待B
ready-state
。如果B
位于ready-state
,B
被锁定且设置为event-state
,则会传播该事件。事件传播完成后,B
将设置为ready-state
。
我可以看到如何通过添加和删除按钮中的类ready-state
来完成与此相近的操作。但是,问题是用户可以连续两次单击按钮,而不是可以设置变量,因此在某些情况下锁定尝试会失败。
有谁知道如何实现一个不会在JavaScript中失败的锁?
答案 0 :(得分:79)
Lock在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解决方案来实现它。
答案 1 :(得分:28)
JavaScript是,在某些版本的Firefox exceptions中只有极少数event-loop concurrent(XMLHttpRequest
onreadystatechange
个处理程序。所以你不必担心在这种情况下锁定。
JavaScript具有基于“事件循环”的并发模型。这个模型与其他语言(如C或Java)中的模型完全不同。
...
JavaScript运行时包含一个消息队列,它是要处理的消息列表。每个消息都与一个函数相关联。当堆栈为空时,将从队列中取出消息并进行处理。处理包括调用关联的函数(从而创建初始堆栈帧)当堆栈再次变为空时,消息处理结束。 / p>
...
在处理任何其他消息之前,每条消息都会被完全处理。这在推理您的程序时提供了一些不错的属性,包括每当一个函数运行时,它都不能被抢占并且会在任何其他代码运行之前完全运行(并且可以修改函数操作的数据)。 这与C不同,例如,如果一个函数在一个线程中运行,它可以在任何时候停止在另一个线程中运行一些其他代码。
此模型的缺点是,如果消息完成时间过长,则Web应用程序无法处理用户交互,例如单击或滚动。浏览器通过“脚本运行时间太长”对话框来缓解此问题。 遵循的一个好习惯是简化邮件处理,如果可能,将一条邮件简化为多条邮件。
有关事件循环并发的更多链接,请参阅E
答案 2 :(得分:6)
锁是多线程系统中所需的概念。即使使用工作线程,也会在工作程序之间按值发送消息,因此不需要锁定。
我怀疑你需要在你的按钮之间设置一个信号量(标记系统)。
答案 3 :(得分:5)
我已经取得了成功mutex-promise。
我同意您在案件中可能不需要锁定的其他答案。但是,从来没有人需要锁定Javascript,这是不正确的。在访问不处理并发的外部资源时,您需要互斥。
答案 4 :(得分:2)
为什么不在完成活动后禁用按钮并启用它?
<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>
快乐的编码!!!
答案 5 :(得分:0)
根据我的情况,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调用,这两个函数将消耗相同的结果。
答案 6 :(得分:0)
锁在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
})
答案 7 :(得分:0)
这是一个简单的锁机制,通过闭包实现
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