如何在JavaScript中实现锁定

时间:2011-03-17 23:57:21

标签: javascript events javascript-events locking deadlock

如何在JavaScript中实现与C#中的lock相当的东西?

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

用户点击按钮BB提出了onclick事件。如果B位于event-state,则会在传播前等待B ready-state。如果B位于ready-stateB被锁定且设置为event-state,则会传播该事件。事件传播完成后,B将设置为ready-state

我可以看到如何通过添加和删除按钮中的类ready-state来完成与此相近的操作。但是,问题是用户可以连续两次单击按钮,而不是可以设置变量,因此在某些情况下锁定尝试会失败。

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

8 个答案:

答案 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 concurrentXMLHttpRequest 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