Может ли прерывание работы JavaScript прерываться?
Я всегда думал, что, поскольку JavaScript был однопоточным, я мог присоединять обработчики событий, не беспокоясь о том, что обработчики выполняются, пока я был в середине выполнения кода. К моему удивлению, я обнаружил, что они могут. Согласно этот ответ, диалоговое окно "Невосприимчивое Script" может вызвать события, которые должны быть подняты, пока script все еще работает.
Я проверил это со следующим кодом:
<script>
function loop() {
var cond;
onblur = function (event) {
cond = false;
};
cond = true;
while (cond)
;
alert('loop exited!');
}
</script>
<button onclick="loop()">loop()</button>
(jsFiddle)
В Firefox 11.0 функция выводит "loop exited" после нажатия кнопки continue. Кажется, что петля приостановлена, и события разрешены для выполнения. Это похоже на Сигнал Unix, который временно изменяет контекст целевого потока. Но это намного опаснее, так как позволяет изменять внешнее состояние.
Это ошибка? Должна ли я больше не зависеть от модели JavaScript с одним потоком исполнения и гарантировать, что все мои скрипты будут повторно введены? Или это недостаток, которого не стоит преследовать, несмотря на то, что основной браузер позволяет это произойти?
Ответы
Ответ 1
Итак, если вы создадите бесконечный цикл, вы повесите свой JavaScript. Diff браузеры будут обрабатывать это по-другому. Firefox 11 для меня подбрасывает окно, в котором отображается ваш script. Chrome сейчас просто работает для меня.
Это должно доказать точку. Никогда не называет alert()
в FF11 или Chrome 17.
while(true){}
alert("sucks");
http://jsfiddle.net/JCKRt/1/
Вы спросили о операторах синхронизации в JavaScript. Есть еще несколько синхронных операторов, которые будут блокировать выполнение JavaScript, например alert()
, confirm()
, синхронные вызовы ajax и многое другое.
Обычно вы хотите избежать каких-либо синхронных вещей в JavaScript! Если вы хотите, чтобы что-то приостановилось, вы можете подумать о дизайне. JavaScript управляется событиями. Вам не нужно, чтобы он вращался в цикле while, потому что ничего на странице будет работать, включая любые события, такие как клики и т.д.
Ответ 2
Я думаю, что проблема возникает, когда вы начинаете заниматься событиями.
Вместо использования цикла while рассмотрите возможность использования рекурсивной функции.
Вот некоторые изменения, которые я сделал для вашего кода, который должен выполняться по желанию.
<head>
<script>
function loop(that) {
var cond;
that.onblur = function (event) {
cond = false;
};
cond = true;
var loop = 0
var xy = function x (){
if(cond == true){
loop++;
setTimeout(function(){xy()},0);
} else {
alert('loop exited! - '+loop);
return true;
}
}
xy();
}
</script>
</head>
<body>
<button onclick="this.focus(); loop(this)">loop()</button>
</body>
Использование setTimeout() с задержкой 0 должно позволить любым событиям входить без каких-либо проблем. Ваш код цикла не будет выполнен почти так же быстро, но вам просто нужно его протестировать и посмотреть.