Разъяснение поведения clearTimeout в IE - PullRequest
4 голосов
/ 02 мая 2011

У меня есть следующий код:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
    "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title></title>
    </head>
<body>
<div id="logger"></div>
<script>

function log(txt) {
    document.getElementById('logger').innerHTML += txt + '<br>';
}

var int = 10;
var a= setTimeout(function(){
    a = null;
    log("A fired!");
    clearTimeout(b);
    b = null;
}, int);

var b = setTimeout(function(){
    b = null;
    log("B fired!");
    clearTimeout(a);
    a = null;
}, int);


</script>

</body>
</html>

Обе функции обратного вызова должны предотвращать срабатывание другого. В Opera, FF и Chrome выполняется только первый (который печатает ″ A запущенный ″). Но когда я запускаю один и тот же код в IE6 и IE8, выполняются оба обратных вызова. Это какая-то ошибка в моем скрипте или это одна из тех ошибок, которые эти браузеры полны? Гарантируют ли clearTimeout () / clearInterval (), что обратный вызов не будет вызываться после их вызова?

Ответы [ 2 ]

3 голосов
/ 25 августа 2011

Я думаю, что происходит так:

  • У JavaScript есть очередь событий.
  • IE обрабатывает тайм-ауты и ставит в очередь два события.
  • Первое событие тайм-аута обрабатывается, и clearTimeout вызывается для B. Однако событие для B уже поставлено в очередь, поэтому оно все равно запускается.
  • обрабатывается второе событие тайм-аута, и вызывается clearTimeout для A.

Я подозреваю, что в IE событие ставится в очередь, и вызов clearTimeout не удаляет событие из очереди событий.

Также возможно, что в том, как IE выдвигает одновременные тайм-ауты в очередь, есть просто причудливость ... Диагностика основной причины может быть достигнута с помощью двух разных тайм-аутов, с использованием 100% циклов обработки ЦП на время x и с помощью очереди / создание временных интервалов в других событиях (возможно, можно добавить события в очередь с помощью window.postMessage () и перехватить их с помощью window.onMessage ()).

Я изменил ваш существующий код, чтобы лучше продемонстрировать проблему. Он ставит в очередь элементы журнала, а не делает их немедленно, потому что вызов метода display () может вызвать разметку или рендеринг, что может легко привести к другим бесполезным помехам.

Редактировать: Вы можете проверить это, используя http://jsbin.com/ucukez/2 - если в браузере возникла ошибка, вы получите "в течение тайм-аута" и"в тайм-ауте B".

Редактировать: это было исправлено в IE9 - я не мог воспроизвести в IE9 / IE10 / IE11.

HTML-код:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>setTimeout queued test</title>
    <script>
        function display(txt) {
            document.getElementById('logger').innerHTML += txt + '<br>';
        }

        var log = {
            items: [],
            push: function(text) {
                this.items.push(text);
            },
            display: function() {
                var items = this.items;
                this.items = [];
                for (var i = 0; i < items.length; i++) {
                    display(items[i]);
                }
            }
        };

        function startTest() {
            var ms = 10;

            display("startTest()");
            log.push('before A setTimeout');
            var a = setTimeout(function(){
                log.push('in A timeout fired');
                display("A fired!");
                log.push('in A clear timer B');
                clearTimeout(b);
                log.push('in A cleared timer B');
            }, ms);
            log.push('after A setTimeout');

            log.push('before B setTimeout');
            var b = setTimeout(function(){
                log.push('in B timeout fired');
                display("B fired!");
                log.push('in B clear timer A');
                clearTimeout(a);
                log.push('in B cleared timer A');
            }, ms);
            log.push('after B setTimeout');

            setTimeout(function(){
                display("");
                display("Displaying logged items:");
                log.display();
            },1000);
        }
    </script>
</head>
<body onload="startTest()">
    <div id="logger"></div>
</body>
</html>
0 голосов
/ 02 мая 2011

Вы устанавливаете тайм-ауты, чтобы они происходили в одно и то же время, и, поскольку они оба являются разветвленными процессами, вы получаете противоречивые результаты

Лучше всего сначала проверить, действительно ли тайм-аут еще так:

var int = 10;
var a= setTimeout(function(){
    if (!a) return;
    a = null;
    log("A fired!");
    clearTimeout(b);
    b = null;
}, int);

var b = setTimeout(function(){
    if (!b) return;
    b = null;
    log("B fired!");
    clearTimeout(a);
    a = null;
}, int);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...