简体   繁体   English

setInterval 和 setTimeout 如何工作?

[英]How does setInterval and setTimeout work?

I was in an awkward situation ,我处于尴尬的境地

I am working with pure JavaScript for almost 3 years, and I know that JavaScript is single-threaded language, and that you can simulate asynchronous execution using setInterval and setTimeout functions,我使用纯 JavaScript 将近 3 年了,我知道 JavaScript 是单线程语言,您可以使用setIntervalsetTimeout函数模拟异步执行,

but when I thought about how they can work I couldn't clearly understand it.但是当我想到它们如何工作时,我无法清楚地理解它。 So how these functions affect execution context?那么这些函数如何影响执行上下文呢?

I suppose that in specific time runs only one part of the code and after it switches to another part.我想在特定时间只运行代码的一部分,然后切换到另一部分。 If so, then would a lot of setInterval or setTimeout calls affect performance?如果是这样,那么很多setIntervalsetTimeout调用会影响性能吗?

Javascript is singled-threaded but the browser is not. Javascript 是单线程的,但浏览器不是。 The browser has at least three threads: Javascript engine thread, UI thread, and timing thread, where the timing of setTimeout and setInterval are done by the timing thread.浏览器至少有三个线程:Javascript引擎线程、UI线程和计时线程,其中setTimeoutsetInterval的计时由计时线程完成。

When calling setTimeout or setInterval , a timer thread in the browser starts counting down and when time up puts the callback function in javascript thread's execution stack.调用setTimeoutsetInterval ,浏览器中的计时器线程开始倒计时,时间到时将回调函数放入 javascript 线程的执行堆栈中。 The callback function is not executed before other functions above it in the stack finishes.回调函数不会在堆栈中位于其上方的其他函数完成之前执行。 So if there are other time-consuming functions being executed when time up, the callback of setTimeout will not finish in time.所以如果time up时还有其他耗时的函数在执行, setTimeout的回调就不会及时完成。

How setTimeout / setInterval work's in JavaScript JavaScript 中的 setTimeout / setInterval 如何工作

Browser has API for Timer function just like API for event ex.浏览器具有定时器功能的 API,就像事件 ex 的 API。

'click' '点击'

'scroll' '滚动'

Assume that you have following code in your application假设您的应用程序中有以下代码

function listener(){
    ...
}

setTimeout(listener, 300)

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

foo()

看看函数执行是如何在 javascript 中工作的

At this point as per our code we wrote above our call stack will look like此时,根据我们在上面编写的代码,我们的调用堆栈将如下所示

Call Stack -> foo调用堆栈 -> foo

And let's assume that foo will take 1s to complete it's execution, as we already defined 1 timeout in our code and we are running it before "foo" complete's it's execution ie at 300ms让我们假设 foo 需要 1s 来完成它的执行,因为我们已经在我们的代码中定义了 1 个超时并且我们在“foo”完成它的执行之前运行它,即在 300ms

What will happen then ?会发生什么?

Does javascript stop executing foo and start executing setTimeout ? javascript 是否停止执行 foo 并开始执行 setTimeout ?

No

As we already know javascript is single threaded so it has to complete execution of foo before moving ahead, but how does browser insure that after execution of foo the "setTimeout" will execute ?正如我们已经知道的 javascript 是单线程的,所以它必须在继续之前完成 foo 的执行,但是浏览器如何确保在执行 foo 之后“setTimeout”将执行?

Here javascript magic comes into picture这里 javascript 魔法出现了

When 300ms is expired the browser "Timer API" kicks in and put the timeout handler into "Message Queue"当 300ms 到期时,浏览器“Timer API”启动并将超时处理程序放入“Message Queue”

At this point "Message Queue" in above image will look like此时上图中的“消息队列”看起来像

Message Queue -> setTimout:listner消息队列 -> setTimeout:listner

And

Call Stack -> foo调用堆栈 -> foo

And when "Call Stack" becomes empty ie foo completes it's execution the "Event Loop" as shown in the image will take the message from message queue and push it into stack当“调用堆栈”变空时,即 foo 完成它的执行,如图所示的“事件循环”将从消息队列中获取消息并将其推入堆栈

The only job of "Event Loop" is when "Call Stack" becomes empty and "Message Queue" has entry in it then dequeue the message form "Message Queue" and push it into "Call Stack" “事件循环”的唯一工作是当“调用堆栈”变空并且“消息队列”中有条目时,然后从“消息队列”中取出消息并将其推入“调用堆栈”

At this point Message Queue in above image will look like此时上图中的消息队列看起来像

Message Queue ->消息队列 ->

And

Call Stack -> listener调用堆栈 -> 监听器

And that's how setTimeout and setInterval works, even though we specify 300 ms in the setTimeout it will execute after "foo" completes it's execution in this case ie after 1s.这就是 setTimeout 和 setInterval 的工作原理,即使我们在 setTimeout 中指定了 300 毫秒,它也会在“foo”完成后执行,在这种情况下,即 1 秒后。 And that's why timer specified in setTimeout/setInterval indicates "Minimum Time" delay for execution of function.这就是为什么在 setTimeout/setInterval 中指定的计时器指示函数执行的“最短时间”延迟。

Javascript is single threaded but browser is not. Javascript 是单线程的,但浏览器不是。

There is 1 stack where function and statements get executed.有 1 个堆栈用于执行函数和语句。 there is 1 queue where function are queued to be executed.有 1 个队列,函数在其中排队等待执行。 there are web APIs which can hold the function for particular time, defined in setTimeout and setInterval in event table.有一些 Web API 可以在特定时间保存函数,在事件表中的 setTimeout 和 setInterval 中定义。

when javascript engine execute js file line by line, if it finds a line as statement or function call it load it on stack and execute but if it is setTimeout or setInterval call, then function handler associated with setTimeout or setInterval is taken out by TIME API (one of web API of browser)and hold it for that time.当 javascript 引擎逐行执行 js 文件时,如果它找到一行作为语句或函数调用,则将其加载到堆栈上并执行,但如果是 setTimeout 或 setInterval 调用,则与 setTimeout 或 setInterval 关联的函数处理程序被 TIME API 取出(浏览器的 Web API 之一)并保留它。

Once this time is over, Time Api put that function at end of execution queue.一旦这个时间结束,Time Api 将该函数放在执行队列的末尾。

Now Execution of that function depends on other functions calls which are ahead of in queue.现在该函数的执行取决于队列中前面的其他函数调用。

Note: this function call is called upon window object.注意:此函数调用是在 window 对象上调用的。

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

Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}窗口{postMessage:ƒ,模糊:ƒ,焦点:ƒ,关闭:ƒ,框架:窗口,...}

JavaScript is a single-threaded scripting language, so it can execute one piece of code at a time (due to its single-threaded nature) each of these blocks of code is “blocking” the progress of other asynchronous events. JavaScript 是一种单线程脚本语言,因此它可以一次执行一段代码(由于其单线程特性),这些代码块中的每一个都“阻塞”了其他异步事件的进程。 This means that when an asynchronous event occurs (like a mouse click, a timer firing, or an XMLHttpRequest completing) it gets queued up to be executed later.这意味着当异步事件发生时(如鼠标单击、计时器触发或 XMLHttpRequest 完成),它会排队等待稍后执行。

setTimeout() when you use setTimeout() it will execute only when its turn comes in a queue, if an earlier event (of setTimeout) blocks due to some reason setTimeout can be delayed than the specified time in setTimeout() function. setTimeout()当您使用 setTimeout() 时,它只会在轮到它进入队列时执行,如果较早的事件(setTimeout)由于某种原因阻塞, setTimeout 可以延迟到 setTimeout() 函数中的指定时间。 during the execution of setTimeout callback function, if any event occurs(eg click event),it gets queued up to be executed later.在 setTimeout 回调函数的执行过程中,如果发生任何事件(例如点击事件),它将排队等待稍后执行。

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

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

setInterval()设置间隔()

  • Similar to setTimeout but continually calls the function (with a delay every time) until it is canceled.类似于 setTimeout 但不断调用该函数(每次都有延迟)直到它被取消。

  • setTimeout code will always have at least a 10ms delay after the setTimeout 代码将始终有至少 10 毫秒的延迟后
    previous callback execution (it may end up being more, but never less) whereas the setInterval will attempt to execute a callback every 10ms regardless of when the last callback was executed.先前的回调执行(最终可能会更多,但绝不会更少)而 setInterval 将尝试每 10 毫秒执行一次回调,而不管最后一次回调是何时执行的。

  • If a timer is blocked from immediately executing it will be delayed如果计时器被阻止立即执行,它将被延迟
    until the next possible point of execution (which will be longer than the desired delay).直到下一个可能的执行点(这将比所需的延迟更长)。 Intervals may execute back-to-back with no delay if they take long enough to execute (longer than the specified如果间隔的执行时间足够长(比指定的时间长),则间隔可以无延迟地连续执行
    delay).延迟)。

Just a note in regards to my experience, If you are going to use setTimeout(), the function will always be delayed (and I mean executed later) or executed after further code which is not 'timeouted'.只是关于我的经验的说明,如果您打算使用 setTimeout(),该函数将始终被延迟(我的意思是稍后执行)或在未“超时”的进一步代码之后执行。 This may happen even with functions which have delay = 0 and is caused by Event Loop.即使对于延迟 = 0 且由事件循环引起的函数,也可能发生这种情况。

See example below:请参阅下面的示例:

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

console.log('First');

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM