setInterval和setTimeout如何工作?

Tar*_*yan 26 javascript browser v8 spidermonkey chakra

我处在一个尴尬的境地,

我使用纯JavaScript已经有近3年了,我知道JavaScript是单线程语言,你可以使用setIntervalsetTimeout函数来模拟异步执行,

但当我想到他们如何工作时,我无法清楚地理解它.那么这些函数如何影响执行上下文?

我想在特定时间内只运行代码的一部分,然后切换到另一部分.如果是这样,那么很多setInterval或者setTimeout 电话会影响性能吗?

CDT*_*CDT 24

Javascript是单线程的,但浏览器不是.浏览器至少有三个主题:Javascript引擎线程,UI线程和定时线程,其中的时间setTimeoutsetInterval由定时线程中完成的.

当调用setTimeoutor时setInterval,浏览器中的计时器线程开始倒计时,并且当时间到时将回调函数放入javascript线程的执行堆栈中.在堆栈中的其他函数完成之前,不执行回调函数.因此,如果在时间到时执行其他耗时的函数,则回调setTimeout将无法及时完成.

  • @SunilGarg你的小提琴不正确.它应该是setTimeout(alert,3000)才能正常工作.执行setTimeout(alert(),3000)会导致首先评估alert(),然后将alert()的结果传递给setTimeout (3认同)

Jay*_*wai 8

setTimeout / setInterval如何在JavaScript中工作

浏览器具有用于计时器功能的API,就像用于事件ex的API一样。

“点击”

'滚动'

假设您的应用程序中包含以下代码

function listener(){
    ...
}

setTimeout(listener, 300)

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

foo()
Run Code Online (Sandbox Code Playgroud)

在javascript中查看函数执行的工作方式

此时,根据我们在调用堆栈上方编写的代码,

调用堆栈-> foo

并假设foo将花费1s来完成其执行,因为我们已经在代码中定义了1个超时,并且我们在“ foo”完成之前即在300ms之前运行它

那会发生什么呢?

javascript是否会停止执行foo并开始执行setTimeout?

没有

我们已经知道javascript是单线程的,因此它必须先完成foo的执行,然后浏览器才能确保在执行foo之后“ setTimeout”将执行?

这里的JavaScript魔术变成了图片

300ms到期后,浏览器“ Timer API”启动,并将超时处理程序放入“ Message Queue”

此时,上图中的“消息队列”看起来像

消息队列-> setTimout:listner

调用堆栈-> foo

当“调用堆栈”为空(即foo完成)时,如图所示,“事件循环”将从消息队列中获取消息并将其推入堆栈

“事件循环”的唯一工作是当“调用堆栈”为空并且其中有“消息队列”条目时,然后使消息形式“消息队列”出队,并将其推入“调用堆栈”

此时,上图中的Message Queue看起来像

消息队列->

调用堆栈->监听器

这就是setTimeout和setInterval的工作方式,即使我们在setTimeout中指定300 ms,在这种情况下,它将在“ foo”完成执行后(即1s之后)执行。这就是为什么在setTimeout / setInterval中指定的计时器指示函数执行的“最小时间”延迟。


Sam*_*ain 6

Javascript 是单线程的,但浏览器不是。

有 1 个堆栈用于执行函数和语句。有 1 个队列,函数在其中排队等待执行。有一些 Web API 可以在特定时间保存函数,在事件表中的 setTimeout 和 setInterval 中定义。

当 javascript 引擎逐行执行 js 文件时,如果它找到一行作为语句或函数调用,则将其加载到堆栈上并执行,但如果是 setTimeout 或 setInterval 调用,则与 setTimeout 或 setInterval 关联的函数处理程序被 TIME API 取出(浏览器的 Web API 之一)并保留它。

一旦这个时间结束,Time Api 将该函数放在执行队列的末尾。

现在该函数的执行取决于队列中前面的其他函数调用。

注意:此函数调用是在 window 对象上调用的。

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

窗口{postMessage:ƒ,模糊:ƒ,焦点:ƒ,关闭:ƒ,框架:窗口,...}