Как реализовать блокировку в JavaScript - PullRequest
67 голосов
/ 18 марта 2011

Как можно реализовать что-то эквивалентное lock в C # в JavaScript?

Итак, чтобы объяснить, что я думаю, простой пример использования:

Кнопка пользовательских нажатий B.B вызывает событие onclick.Если B находится в event-state, то событие ожидает, пока B окажется в ready-state, прежде чем распространится.Если B находится в ready-state, B заблокирован и имеет значение event-state, то событие распространяется.Когда распространение события завершено, B устанавливается на ready-state.

Я мог видеть, как можно сделать что-то близкое к этому, просто добавив и удалив класс ready-state из кнопки.Однако проблема заключается в том, что пользователь может дважды нажать кнопку быстрее, чем может быть установлена ​​переменная, поэтому в некоторых случаях эта попытка блокировки завершится неудачей.

Кто-нибудь знает, как реализовать блокировкучто не подведет в JavaScript?

Ответы [ 6 ]

79 голосов
/ 18 марта 2011

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.

28 голосов
/ 18 марта 2011

JavaScript, с очень немногими исключениями (XMLHttpRequest onreadystatechange обработчики в некоторых версиях Firefox) параллельный цикл обработки событий . Так что в этом случае вам не нужно беспокоиться о блокировке.

JavaScript имеет модель параллелизма, основанную на "цикле событий". Эта модель сильно отличается от модели в других языках, таких как C или Java.

...

Среда выполнения JavaScript содержит очередь сообщений, представляющую собой список сообщений, подлежащих обработке. С каждым сообщением связана функция. Когда стек пуст, сообщение извлекается из очереди и обрабатывается. Обработка состоит из вызова связанной функции (и, следовательно, создания начального кадра стека). Обработка сообщения заканчивается, когда стек снова становится пустым.

...

Каждое сообщение обрабатывается полностью перед обработкой любого другого сообщения. Это дает некоторые приятные свойства при рассуждении о вашей программе, включая тот факт, что всякий раз, когда функция запускается, она не может быть прервана и будет выполняться полностью перед выполнением любого другого кода (и может изменять данные, которыми манипулирует функция). Это отличается от C, например, если функция запускается в потоке, ее можно остановить в любой момент для запуска другого кода в другом потоке.

Недостатком этой модели является то, что если сообщение занимает слишком много времени, веб-приложение не может обрабатывать взаимодействия с пользователем, такие как щелчок или прокрутка. Браузер смягчает это с помощью диалога «скрипт слишком долго запускается». Хорошей практикой является сокращение обработки сообщений и, если возможно, разбиение одного сообщения на несколько сообщений.

Дополнительные ссылки по параллелизму в цикле событий см. E

6 голосов
/ 24 декабря 2016

У меня был успех мьютекс-обещание .

Я согласен с другими ответами, что вам может не потребоваться блокировка в вашем случае.Но это не правда, что в Javascript никогда не требуется блокировка.Вам нужна взаимная исключительность при доступе к внешним ресурсам, которые не поддерживают параллелизм.

6 голосов
/ 08 июня 2011

Замки - это концепция, необходимая в многопоточной системе.Даже с рабочими потоками сообщения передаются по значению между рабочими, поэтому блокировка не нужна.

Я подозреваю, что вам нужно просто установить семафор (систему маркировки) между кнопками.

2 голосов
/ 08 июня 2011

Почему бы вам не отключить кнопку и не включить ее после завершения мероприятия?

<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>

Счастливого кодирования !!!

0 голосов
/ 25 января 2016

Некоторое дополнение к ответу 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, и эти две функции будут использовать один и тот же результат.

...