5 вещей, которые вы могли не знать о setTimeout

JavaScript
5 вещей, которые вы могли не знать о setTimeout

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

Я не буду здесь повторять, что setTimeout — это макрозадача, метод для выполнения асинхронных функций в JavaScript, и я не буду использовать его для реализации Promise, соответствующего спецификации Promises/A+. Потому что они слишком простые, слишком простые! То, что я собираюсь представить сегодня, может быть чем-то, чего вы еще не знаетеsetTimeoutХолодное знание... (Все следующие случаи выполняются в Chrome, пожалуйста, не стесняйтесь есть)

1. Увеличивается ли интервал времени setTimeout сам по себе?

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

Давайте проведем эксперимент для проверки, просто откройте браузер Chrome, чтобы перейти в режим разработчика, введите следующий код в консоли консоли и нажмите Enter:

var timer = setTimeout(function fn() {
    timer = setTimeout(fn, 500)
    console.log(new Date().getSeconds())
}, 500)

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

Ну, мы можем очистить его!clearTimeout(timer)использоватьsetIntervalполучит тот же эффект.

2. Когда выполняется setTimeout не зависит от установленного мной времени?

Сначала посмотрите на код:

function fn() {
    setTimeout(() => {
        console.log('go')
    }, 1)
}

Когда мы выполним функцию fn, она будет распечатана еще через 1 миллисекунду.go, Тогда давайте изменим этот метод.

function fn() {
    for (var i = 0; i < 10000; i++) {
       console.log(i)
    }
    setTimeout(() => {
        console.log('go')
    }, 1)
}

Давайте снова выполним приведенный выше код,goБудет ли он также печатать сразу после 1 мс?

Студенты, которые знают, могут пропустить это, Учащимся, которые мало что знают или имеют неясное представление об этой концепции, рекомендуется прочитать этот абзац. Здесь мы систематически просматриваем точки знаний и пытаемся объяснить вам причины как можно понятнее.

Как мы все знаем, JavaScript в браузере является однопоточным, и у некоторых студентов здесь могут возникнуть сомнения.HTML5 предлагает стандарт Web Worker, который позволяет сценариям JavaScript создавать несколько потоков. Многопоточность здесь состоит из основного потока и нескольких подпотоков, а подпотоки полностью контролируются основным потоком. Так что мы все еще можем считать его все еще однопоточным.

Итак, каковы характеристики одного потока? То есть каждый должен выстроиться в очередь, чтобы что-то сделать. Вот важное понятие -очередь сообщений.

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

Задачи в очереди сообщений включают события рендеринга, события взаимодействия с пользователем, события выполнения сценариев, завершение сетевого запроса, события завершения чтения и записи файлов, таймеры и многое другое. Сегодня мы в основном познакомимся с таймером. Таймер инкапсулируется в макрозадачу с помощью асинхронной функции обратного вызова, а затем добавляется в конец очереди сообщений. Если существует несколько очередей сообщений таймера, как они устроены? Как вы понимаете, некоторые асинхронно выполняемые задачи хранятся в другой специальной очереди сообщений. В этой специальной очереди сообщений хранятся все асинхронные задачи. Мы можем назвать ее асинхронной очередью сообщений. Задачи в этой очереди асинхронных сообщений будут в конце концов выполняться задачи в основной очереди сообщений выполнены.

Таким образом, можно сказать, почему setTimeout в приведенном выше коде не выполняется вовремя через 1 миллисекунду. Поскольку цикл for все еще занимает основной поток и не закончил выполнение, например, товары на конвейерной ленте слишком тяжелые и слишком большие, чтобы их можно было снять на некоторое время, независимо от того, кто отстает, они должны ждать меня.

Три, setTimeout вложен с интервалом не менее 4 миллисекунд.

Выше мы написали циклический таймер с setTimeout. Выполняйте каждые 500 миллисекунд и продолжайте цикл. Минимальное время, которое можно установить здесь, составляет миллисекунды 4. Если вы установите его меньше, чем миллисекунды 4, то он будет выполняться один раз каждые 4 миллисекунды по умолчанию.

var timer = setTimeout(function a() {
    timer = setTimeout(a, 2)
    console.log(new Date().getMilliseconds())
}, 2)

На самом деле в первых 5-ти исполнениях временной интервал будет 2 миллисекунды, а минимальный временной интервал каждого последующего вызова 4 миллисекунды. Причина этого в том, что в Chrome, если таймер вложен и вызывается более 5 раз, система решит, что метод функции заблокирован.Если интервал вызова таймера меньше 4 миллисекунд, браузер между вызовами устанавливается на 4 миллисекунды.

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

Все браузеры Chrome, Safari и Firefox хранят значения задержки в битах 32. Максимальное число, которое может быть сохранено в битах 32, составляет 21 47483647, что эквивалентно 24,8 дням. Тогда это означает, что значение задержки, установленное setTimeout, превышает 2 147 483 647 миллисекунд и будет переполнено.

function fn() {
    setTimeout(() => {
        console.log('go')
    }, 2147483648)
}

Как показано в приведенном выше коде, выполнение функции fn приведет к немедленной печати.

5. setTimeout 1 не обязательно больше 0

Чтобы так сказать? Сначала посмотрите на код:

function fn() {
    setTimeout(() => {
        console.log('go')
    }, 1)
    
    setTimeout(() => {
        console.log('on')
    }, 0)
}

В приведенном выше коде каков порядок печати выполнения функции fn? Интуитивно первая функция выполняется через 1 миллисекунду, а вторая функция выполняется через 0 миллисекунд, поэтому сначала напечатайте, а затем напечатайте go. Но оказалось, что это не так.

Суммировать

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

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

for (var i = 0; i < 10; i++) {
   setTimeout(() => {
     console.log(i)
   })
}

Каков результат выполнения вышеописанного? Это не должно быть сложно для всех, тогда спросите, как заставить его выводить от 0 до 9, если разрешено только изменять тело метода в цикле for?

Ответ появится через 5 секунд...

for (var i = 0; i < 10; i++) {
// setTimeout(() => {
     console.log(i)
// })
}