Неожиданное поведение: Javascript, setTimeout () и IIFE - PullRequest
0 голосов
/ 02 января 2019

Javascript, цикл обработки событий, setTimeout, IIFE, закрытие

Основываясь на ссылках ниже, я понимаю следующий код:

setTimeout () не блокируется и обрабатывается веб-API браузера, который помещает обратные вызовы в очередь обратных вызовов после завершения таймера. Затем цикл обработки событий ожидает освобождения стека вызовов для выполнения каждого обратного вызова по очереди. Закрытие setTimeout закрывает анонимный IIFE и имеет правильное значение индекса для каждой итерации.

for(var i = 0; i < 3; i++){
    (function(index){
        setTimeout(function(){
            console.log(index);
        }, 5000);
    })(i);
    console.log("loop="+i);
}
/*Output in console is
loop=0
loop=1
loop=2
//after 5 seconds
0
1
2
*/

Я ищу объяснение того, что происходит со следующим кодом в Chrome.

for (var i = 0; i < 3; i++) {
    setTimeout(
        function(index) { 
            console.log(index);
        }(i), 5000
    );
    console.log("loop="+i);
}
/* Output in console without any delay is:
0
loop=0
1
loop=1
2
loop=2
*/

Почему 'console.log (index)' выполняется немедленно, без 5-секундной задержки?

Как веб-API выполняет setTimeout () с обратным вызовом как IIFE?

Есть ли какие-либо обратные вызовы, помещенные в очередь обратных вызовов?

Перемещает ли цикл обработки событий какие-либо обратные вызовы в стек вызовов?

Или setTimeout () игнорируется и его обратный вызов выполняется немедленно в стеке вызовов?


Рекомендации, с которыми я консультировался:

Филипп Робертс: Какого черта цикл событий в любом случае? | ЗАО на ЕС 2014 https://www.youtube.com/watch?v=8aGhZQkoFbQ

Филипп Робертс Помогите Я застрял в цикле событий 2016 https://www.youtube.com/watch?v=6MXRNXXgP_0

стек вызовов и цикл событий https://www.youtube.com/watch?v=mk0lu9MKBto

Закрытие JavaScript внутри циклов - простой практический пример

Использовать IIFE в setTimeout в цикле, но почему?

Ответы [ 3 ]

0 голосов
/ 02 января 2019

Во втором примере вы не передаете функцию в setTimeout, а скорее передаете ее результат вызова функции (в данном случае это void).

        function(index) { 
            console.log(index);
        }(i)

Вы видите, что в этом примере ваша функция вызывается немедленно, поэтому позже не к чему вызывать, и консоль регистрирует по порядку.

0 голосов
/ 02 января 2019

Я ищу объяснение того, что происходит со следующими код в Chrome.

for (var i = 0; i < 3; i++) {
    setTimeout(
        function(index) { 
            console.log(index);
        }(i), 5000
    );
    console.log("loop="+i);
}
/* Output in console without any delay is:
0
loop=0
1
loop=1
2
loop=2
*/

Рассмотрим следующее утверждение:

function(index) { 
    console.log(index);
}(i)

Это анонимная функция , которая выполняется немедленно (скобки '()' в конце выполняют функцию): см. Синтаксис function(param) {...}(). Таким образом, эффект заключается в том, что для каждой итерации приведенный выше код выполняется немедленно.

Результат (как вы видите):

0
1
2

setTimeout в MDN . метод ожидает функцию (которая будет выполнена после истечения таймера) или код в качестве первого параметра. В этом случае у вас есть код (не функция), который выполняется немедленно. Итак, вы сразу видите результат.

Задержка в 5 секунд не действует, она никогда не используется. После задержки выполнять нечего.

Эффект такой же в Firefox тоже.

Вы можете попробовать код без скобок в конце анонимной функции и посмотреть, что произойдет:

function(index) { 
    console.log(index);
}

Функция будет выполняться с задержкой в ​​пять секунд, в этом случае!

0 голосов
/ 02 января 2019

In

setTimeout(
    function(index) { 
        console.log(index);
    }(i), 5000
);

Вы вызываете первый аргумент, переданный setTimeout немедленно .Когда интерпретатор встречает строку setTimeout, он сначала пытается преобразовать все свои аргументы в значения.Первый аргумент - это вызов функции, поэтому он вызывает эту функцию в ожидании того, что она преобразуется в другую функцию - точно так же, как можно было бы сделать

setTimeout(makeFn('foo'), 5000);

, где makeFn возвращаетфункция.

Итак, в вашем коде

    function(index) { 
        console.log(index);
    }(i)

запускается немедленно, но ничего не возвращает - интерпретатор разрешает строку setTimeout в

setTimeout(undefined, 5000);

, но undefined не является функцией, поэтому ничего асинхронного не ставится в очередь.

У вас нет IIFE здесь - поместите всю строку setTimeout в IIFE вместо:

for (var i = 0; i < 3; i++) {
  ((i) => {
    setTimeout(
      function() {
        console.log(i);
      }, 500
    );
    console.log("loop=" + i);
  })(i);
}

(или, конечно, вместо var используйте const или let - лучше всего избегать var, сфера его подъема и функций очень не интуитивнаи требует подробных обходных путей, подобных этим в for loop)

for (let i = 0; i < 3; i++) {
  setTimeout(
    function() {
      console.log(i);
    }, 500
  );
  console.log("loop=" + i);
}
...