Может ли поток выполнения JavaScript быть прерван? - PullRequest
20 голосов
/ 20 марта 2012

Я всегда думал, что, поскольку JavaScript был однопоточным, я мог присоединять обработчики событий, не беспокоясь о том, что обработчики выполняются, когда я был в середине выполнения кода. К моему удивлению, я обнаружил, что они могут. В соответствии с этим ответом диалоговое окно «Сценарий не отвечает» может вызывать события , пока сценарий еще выполняется.

Я проверил это с помощью следующего кода:

<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 функция выводит «цикл завершен» после нажатия кнопки «Продолжить». Цикл кажется приостановленным, и события могут выполняться. Это похоже на Unix-сигнал , который временно меняет контекст целевого потока. Но это намного опаснее, поскольку позволяет изменять внешнее состояние.

Это ошибка? Должен ли я больше не зависеть от модели JavaScript с единым потоком выполнения и гарантировать, что все мои сценарии являются входящими повторно? Или это недостаток, который не стоит искать, несмотря на то, что крупный браузер позволяет этому случиться?

Ответы [ 2 ]

2 голосов
/ 20 марта 2012

Так что да, если вы создадите бесконечный цикл, вы повесите свой JavaScript. Разные браузеры справятся с этим по-разному. Firefox 11 для меня открывает окно, в котором говорится, что ваш скрипт завис. Хром сейчас просто крутится для меня.

Это должно доказать суть. Никогда не звонит alert() в FF11 или Chrome 17.

while(true){}
alert("sucks");

http://jsfiddle.net/JCKRt/1/

Вы спрашивали о операторах синхронизации в JavaScript. Есть несколько других синхронных операторов, которые блокируют выполнение JavaScript, таких как alert(), confirm(), синхронные вызовы ajax и т. Д.

Вы обычно хотите избежать каких-либо синхронных вещей в JavaScript! Если вы хотите, чтобы вещи приостановились, вы можете пересмотреть дизайн. JavaScript управляемый событиями . Вам не нужно, чтобы он вращался в цикле while, потому что ничего на странице не будет работать, включая любые события, такие как щелчки и т. Д.

0 голосов
/ 25 марта 2012

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

Вместо использования цикла 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 должно позволить любым событиям переходить без каких-либо проблем.Ваш код цикла не будет выполнен почти так же быстро, но вам просто нужно проверить его и посмотреть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...