Вы можете отменить привязку вашего обработчика с помощью .off
, но есть предостережение; если вы делаете это, просто предотвратите повторный запуск обработчика, когда он уже запущен, вам нужно отложить повторную привязку обработчика.
Например, рассмотрим этот код, который использует 5-секундный горячий сон, чтобы имитировать что-то синхронное и вычислительно дорогое, выполняемое из обработчика (например, тяжелые манипуляции с DOM):
<button id="foo">Click Me!</div>
<script>
function waitForFiveSeconds() {
var startTime = new Date();
while (new Date() - startTime < 5000) {}
}
$('#foo').click(function handler() {
// BAD CODE, DON'T COPY AND PASTE ME!
$('#foo').off('click');
console.log('Hello, World!');
waitForFiveSeconds();
$('#foo').click(handler);
});
</script>
Это не сработает. Как вы можете видеть, если вы попробуете это в в этом JSFiddle , если вы нажмете кнопку, когда обработчик уже выполняется, обработчик будет выполнен второй раз после завершения первого выполнения. Более того, по крайней мере в Chrome и Firefox, это было бы верно, даже если вы не использовали jQuery и использовали addEventListener
и removeEventListener
для добавления и удаления обработчика вместо этого , Браузер выполняет обработчик после первого щелчка, отменяет привязку и повторную привязку обработчика, и , а затем обрабатывает второй щелчок и проверяет, есть ли обработчик щелчка для выполнения.
Чтобы обойти это, вам нужно отложить повторное связывание обработчика, используя setTimeout
, чтобы щелчки, которые происходят во время выполнения первого обработчика, были обработаны до повторного присоединения обработчик.
<button id="foo">Click Me!</div>
<script>
function waitForFiveSeconds() {
var startTime = new Date();
while (new Date() - startTime < 5000) {}
}
$('#foo').click(function handler() {
$('#foo').off('click');
console.log('Hello, World!');
waitForFiveSeconds();
// Defer rebinding the handler, so that any clicks that happened while
// it was unbound get processed first.
setTimeout(function () {
$('#foo').click(handler);
}, 0);
});
</script>
Вы можете увидеть это в действии на этом модифицированном JSFiddle .
Естественно, в этом нет необходимости, если то, что вы делаете в своем обработчике, уже асинхронно, поскольку тогда вы уже передаете управление браузеру и позволяете ему сбрасывать все события щелчка, прежде чем перепривязывать свой обработчик. Например, такой код будет хорошо работать без setTimeout
вызова:
<button id="foo">Save Stuff</div>
<script>
$('#foo').click(function handler() {
$('#foo').off('click');
$.post( "/some_api/save_stuff", function() {
$('#foo').click(handler);
});
});
</script>