Понять механизм запуска JS из setTimeout

JavaScript
Понять механизм запуска JS из setTimeout

последовательность

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

пример

console.log(1);
setTimeout(function () {
    console.log(2);
}, 0);
console.log(3);

В: Каков окончательный заказ на печать? (Если вы не понимаете механизм работы js, вы ответите неправильно)

правильный ответ:1 3 2

Анализ: Независимо от того, является ли время выполнения Settimeout 0 или 1000, результат должен выводить 3 первого, а затем выводить 2. Это проблема операционного механизма JS, который часто проверяет. Далее мы представим концепцию, которую JavaScript является однопотоком.

Одиночный поток JavaScript

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

С точки зрения непрофессионала: JS может делать только одну вещь за раз, что часто называют «блокировка исполнения".

очередь задач

Так как же однопоточный JavaScript обеспечивает «неблокирующее выполнение»?

отвечать:асинхронныйДобиться неблокировки легко, поэтому в JavaScript для трудоемких операций или операций с неопределенным временем использование асинхронности стало неизбежным выбором.

Как происходит асинхронная обработка таймера в функции обратного вызова при нажатии на событие, связь AJAX, как происходит эта асинхронная обработка?

отвечать:очередь задач

Все задачи можно разделить на два типа, одна — синхронная задача (synchronous), другая — асинхронная задача (asynchronous).

Очередь задач: очередь «первым поступил — первым обслужен», в которой хранятся различные события и задачи.

Синхронизировать задачу

Синхронные задачи: задачи, поставленные в очередь на выполнение в основном потоке, и последняя задача может быть выполнена только после завершения выполнения первой задачи.

  • выход Такие как:console.log()
  • Оператор переменной
  • Синхронная функция: если вызывающая сторона может получить ожидаемое возвращаемое значение или увидеть ожидаемый эффект при возврате функции, то функция является синхронной.

асинхронная задача

  • setTimeout и setInterval
  • DOM-события
  • Promise
  • process.nextTick
  • fs.readFile
  • http.get
  • Асинхронная функция: если вызывающий объект не может получить ожидаемый результат при возврате функции, но должен получить его определенными средствами в будущем, то функция является асинхронной.

Кроме того, очередь задач делится на макро-задачи (macro-задачи) и микро-задачи (микро-задачи), в стандарте ES5 они называются задачами и заданиями соответственно.

задача макроса

  1. I/O
  2. setTimeout
  3. setInterval
  4. setImmdiate
  5. requestAnimationFrame

микрозадачи

  1. process.nextTick
  2. Promise
  3. Promise.then
  4. MutationObserver

Порядок выполнения макрозадач и микрозадач

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

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

Механизм работы setTimeout

Механизм работы setTimeout и setInterval таков:Переместите указанный код из этого исполнения, дождитесь следующего цикла Event Loop, а затем проверьте, достигнуто ли указанное время. Если он приходит, выполните соответствующий код; если нет, подождите до следующего раунда цикла событий, чтобы переоценить.

Это означает, что код, заданный setTimeout, не будет выполняться до тех пор, пока не будет выполнен весь синхронный код, выполняемый на этот раз.

приоритетное отношение: чтобы приостановить асинхронную задачу, сначала выполните синхронную задачу, а затем ответьте на асинхронную задачу после выполнения синхронной задачи.

Расширенные вопросы

console.log('A');
setTimeout(function () {
    console.log('B');
}, 0);
while (1) {}

Угадайте, что выведет эта программа?

отвечать:A

Примечание. Рекомендуется сначала закомментировать код блока кода цикла while, а после выполнения принудительно удалить процесс, иначе это вызовет ""приостановленная анимация".

Синхронный вывод очередиAПосле этого вwhile(true){}В бесконечном цикле асинхронные задачи выполняться не будут.

похоже, иногдаaddEventListener()Метод прослушивания события кликаclick, пользователь застрянет при нажатии кнопки, потому что текущий JS обрабатывает синхронную очередь и не можетclickСобытие триггера помещается в стек выполнения, оно не будет выполнено, и будет "притворная смерть".

Регулярно получать данные об обновлении интерфейса

for (var i = 0; i < 4; i++) {
    setTimeout(function () {
        console.log(i);
    }, 1000);
}

Результат вывода: вывод вместе через 1 с:4 4 4 4

Цикл for является синхронной задачей, почему он выводит четыре четверки подряд?

Ответ: Потому что естьвремя постановки в очередь, даже если время выполнения изменить с 1000 на 0, оно все равно выводит четыре четверки.

Так как же возникла и решилась эта проблема? пожалуйста, читайте дальше

Время выполнения асинхронной очереди

Когда выполняется асинхронная задача, будет ли она помещена непосредственно в асинхронную очередь?Ответ не обязательно.

Поскольку в браузере есть модуль таймера,Таймер не будет помещать асинхронную задачу в асинхронную очередь до тех пор, пока не истечет время выполнения..

Во время выполнения тела цикла for setTimeout не помещается в асинхронную очередь, а передается модулю таймера. 4 тела цикла выполняются очень быстро (менее 1 мс). Таймер не поместит оператор setTimeout в асинхронную очередь до установленного времени.

Даже если время выполнения, установленное setTimeout, равно 0 миллисекундам, оно считается как 4 миллисекунды..

Это объясняет, почему приведенный выше вопрос выводит четыре четверки подряд.

Стандарт HTML5 определяетsetTimeout()Минимальное значение второго параметра, самого короткого интервала, не должно быть меньше 4 миллисекунд. Если оно упадет ниже этого значения, оно автоматически увеличится. До этого старые браузеры устанавливали минимальный интервал в 10 миллисекунд.

Периодические вызовы setTimeout с использованием замыканий

for (let i = 0; i < 4; i++) {
    (function (j) {
        setTimeout(function () {
            console.log(j);
        }, 1000 * i)
    })(i);
}

После выполнения значение будет выводиться каждые 1 с, а именно:0 1 2 3

  • Этот метод используется с умомIIFEОбъявите функциональное выражение, которое выполняется для решения проблем, вызванных замыканиями.
  • Изменил var на let, используя синтаксис ES6.

также доступно здесьsetInterval()метод для реализации прерывистых вызовов.

Видеть:Разница между setTimeout и setInterval

Использование передачи параметров базовых типов в JS является функциональной реализацией передачи по значению.

var output = function (i) {
    setTimeout(function () {
        console.log(i);

    }, 1000 * i)
}
for (let i = 0; i < 4; i++) {
    output(i);
}

После выполнения значение будет выводиться каждые 1 с, а именно:0 1 2 3

Принцип реализации: прошло в прошломiЗначение копируется.

Обещанные решения

const tasks = [];

const output = (i) => new Promise((resolve) => {
    setTimeout(() => {
        console.log(i);
        resolve();
    }, 1000 * i);

});

//生成全部的异步操作
for (var i = 0; i < 5; i++) {
    tasks.push(output(i));
}
//同步操作完成后,输出最后的i
Promise.all(tasks).then(() => {
    setTimeout(() => {
        console.log(i);
    }, 1000)
})

После выполнения значение будет выводиться каждые 1 с, а именно:0 1 2 3 4 5

Преимущества: улучшенная читаемость кода.

Примечание. Если отказ от обещания не будет обработан, ошибка будет выброшена в черную дыру.

Решение, использующее функцию асинхронного ожидания в ES7 (рекомендуется)

const sleep = (timeountMS) => new Promise((resolve) => {
    setTimeout(resolve, timeountMS);
});

(async () => { //声明即执行的async
    for (var i = 0; i < 5; i++) {
        await sleep(1000);
        console.log(i);
    }

    await sleep(1000);
    console.log(i);

})();

После выполнения значение будет выводиться каждые 1 с, а именно:0 1 2 3 4 5

Цикл событий Цикл событий

图解Event Loop

Основной поток считывает события из очереди задач, этот процесс цикличен, поэтому весь механизм работы также называетсяEvent Loop.

Иногда setTimeout явно пишет задержку в 3 секунды, а на самом деле выполняет функцию за 5 или 6 секунд, в чем причина этого?

Ответ: setTimeout иВремя выполнения не гарантируется, своевременная реализация зависит отЯвляется ли поток JavaScript переполненным или бездействующим.

Когда JS-движок браузера встречает setTimeout, он не будет помещен в асинхронную очередь сразу после его удаления, а после выполнения синхронной задачи модуль таймера будет помещен в асинхронную очередь через установленное время. Движок js находит, что в синхронной очереди выполнять нечего, то есть когда работающий стек пуст, он читает из асинхронной очереди, а затем кладет в работающий стек для выполнения. Таким образом, у setTimeout может быть больше времени для ожидания потока.

В это время тело функции setTimeout становится задачей выполнения в рабочем стеке. Рабочий стек пуст, а затем отслеживает, есть ли задачи для выполнения в асинхронной очереди. Если есть, она продолжает выполняться. цикл называется циклом событий.

Суммировать

JavaScript обеспечивает асинхронность за счет цикла обработки событий и координации потоков браузера. Синхронизация может обеспечить постоянный порядок, но легко вызвать блокировку; асинхронность может решить проблему блокировки, но она изменит порядок.

Распределяем очки знаний:

  • Поймите концепцию одного потока в JS: делайте одно за раз
  • Понимание задач Очередь: синхронные задачи, асинхронные задачи
  • Понимание циклов событий
  • Узнайте, какие операторы помещаются в очередь асинхронных задач.
  • Понимать, когда операторы помещаются в очередь асинхронных задач

В конце концов, я надеюсь, что вы что-то почерпнете после прочтения. 🤠