Как работают setInterval и setTimeout?

Я был в неудобной ситуации,

Я работаю с чистым JavaScript уже почти 3 года, и я знаю, что JavaScript - это однопоточный язык, и вы можете имитировать асинхронное выполнение с помощью функций setInterval и setTimeout,

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

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

Ответ 1

Javascript выделен, но браузера нет. В браузере есть по крайней мере три потока: поток двигателя Javascript, поток пользовательского интерфейса и временной поток, где время setTimeout и setInterval выполняется с помощью временной синхронизации.

При вызове setTimeout или setInterval поток таймера в браузере начинает отсчет, и когда время запускает функцию обратного вызова в стеке выполнения потока javascript. Функция обратного вызова не выполняется перед тем, как другие функции над ним завершаются в стеке. Поэтому, если во время выполнения выполняются другие трудоемкие функции, обратный вызов setTimeout не будет завершен вовремя.

Ответ 2

Как setTimeout/setInterval работает в JavaScript

У браузера есть API для функции Timer, как API для события ex.

'click'

'свитка'

Предположим, что у вас есть следующий код в приложении

function listener(){
    ...
}

setTimeout(listener, 300)

function foo(){
    for(var i = 0; i < 10000; i++){
        console.log(i)
    }
}

foo()

See How Function Execution work's in javascript

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

Стек вызовов → foo

И пусть предположим, что foo займет 1s, чтобы завершить его выполнение, поскольку мы уже определили 1 тайм-аут в нашем коде, и мы запускаем его, прежде чем "foo" завершит его выполнение i.e при 300ms

Что будет потом?

Выполняет ли javascript выполнение foo и начинает выполнение setTimeout?

Нет

Как мы уже знаем, javascript является однопоточным, поэтому он должен завершить выполнение foo, прежде чем двигаться дальше, но как браузер застрахован от того, что после выполнения foo будет выполняться "setTimeout"?

Здесь маска javascript входит в картину

При истечении 300 мс браузер "Timer API" запускается и помещает обработчик тайм-аута в "очередь сообщений"

В этот момент "Очередь сообщений" в приведенном выше изображении будет выглядеть как

Очередь сообщений → setTimout: listner

И

Стек вызовов → foo

И когда "Стек вызовов" становится пустым, i.e foo завершает его выполнение "Event Loop", как показано на изображении, будет принимать сообщение из очереди сообщений и вставлять его в стек

Единственное задание "Event Loop" - это когда "Call Stack" становится пустым, а "Message Queue" имеет запись в нем, а затем деактивирует форму сообщения "Очередь сообщений" и нажимает ее в "стек вызовов"

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

Очередь сообщений →

И

Вызов стека → прослушиватель

И то, как работают setTimeout и setInterval, хотя мы задаем 300 мс в setTimeout, он будет выполняться после того, как "foo" завершит его выполнение в этом случае i.e после 1s. И поэтому таймер, указанный в setTimeout/setInterval, указывает на "Минимальное время" для выполнения функции.

Ответ 3

Javascript является однопоточным, а браузер - нет.

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

По истечении этого времени Time Api помещает эту функцию в конец очереди выполнения.

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

Примечание: этот вызов функции вызывается для объекта окна.

setTimeout(function() {console.log(this)}, 300)

Окно {postMessage: ƒ, размытие: ƒ, фокус: ƒ, закрытие: ƒ, кадры: окно,…}

Ответ 4

JavaScript - это однопоточный язык сценариев, поэтому он может выполнять один фрагмент кода за раз (из-за своей однопоточной природы), каждый из этих блоков кода "блокирует" выполнение других асинхронных событий. Это означает, что когда происходит асинхронное событие (например, щелчок мышью, срабатывание таймера или завершение XMLHttpRequest), оно ставится в очередь для выполнения позже.

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

setTimeout(function(){
  /* Some long block of code... */
  setTimeout(arguments.callee, 10);
}, 10);

setInterval(function(){
  /* Some long block of code... */
}, 10);

setInterval()

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

  • Код setTimeout всегда будет иметь задержку не менее 10 мс после
    предыдущее выполнение обратного вызова (в конечном итоге оно может быть больше, но никогда меньше), тогда как setInterval будет пытаться выполнить обратный вызов каждые 10 мс независимо от того, когда был выполнен последний обратный вызов.

  • Если таймер заблокирован от немедленного выполнения, он будет отложен
    до следующей возможной точки исполнения (которая будет дольше, чем желаемая задержка). Интервалы могут выполняться вплотную без задержки, если они выполняются достаточно долго (дольше, чем указано
    задержка).

Ответ 5

Просто примечание в отношении моего опыта: если вы собираетесь использовать setTimeout(), функция всегда будет отложена (и я имею в виду выполнено позже) или будет выполнена после следующего кода, который не 'timeouted'. Это может произойти даже с функциями, которые имеют задержку = 0 и вызваны циклом событий.

Смотрите пример ниже:

setTimeout(function() {
    console.log('Second');
}, 0)

console.log('First');