宝哥软件园

javascript定时器工作原理分析

编辑:宝哥软件园 来源:互联网 时间:2021-09-07

setTimeout()

MDN将setTimeout定义为:

在指定的延迟时间后调用函数或执行代码片段。

语法

setTimeout的语法很简单,第一个参数是回调函数,第二个参数是延迟时间。该函数返回一个数字类型的标识唯一标识符,该标识符可以用作清除超时的参数来取消计时器:

var timeoutID=window.setTimeout(代码,延迟);IE0还支持传入回调参数:

var timeoutID=window . settimeout(func,delay,[param1,param2,]);setInterval()

MDN将设置间隔定义为:

定期调用一个函数或执行一段代码。

SetInterval和setTimeout的用法相同,因此这里不列出它们。

第二个参数(延迟)的描述

由于javascript的事件循环机制,第二个参数并不意味着回调函数将在延迟毫秒后立即执行,而是试图将回调函数添加到事件队列中。实际上,setTimeout和setInterval在处理这一点上是不同的:

SetTimeout:延迟毫秒后,将回调函数直接添加到事件队列中。SetInterval:延迟毫秒后,首先检查事件队列中是否有尚未执行的回调函数(SetInterval的回调函数)。如果有,不要给事件队列添加回调函数。因此,当我们的代码中有耗时的任务时,计时器不会像我们想象的那样工作。

通过例子理解

下面的代码原本希望在100毫秒和200毫秒时调用回调函数(也就是说,只是等待100毫秒):

var timerstart 1=now();SetTimeout(function(){ console . log('第一个SetTimeout回调执行等待时间:',now()-timerstart 1);var timerstart 2=now();SetTimeout(function(){ console . log('第二个SetTimeout回调执行等待时间:',now()-timerstart 2);}, 100);}, 100);//输出://第一次setTimeout回调执行等待时间:106//第二次setTimeout回调执行等待时间:107。这个结果看起来和我们想象的完全一样,但是一旦我们将耗时的任务添加到代码中,结果就不是我们预期的那样了:

var timerstart 1=now();SetTimeout(function(){ console . log('第一个SetTimeout回调执行等待时间:',now()-timerstart 1);var timerstart 2=now();SetTimeout(function(){ console . log('第二个SetTimeout回调执行等待时间:',now()-timerstart 2);}, 100);heavyTask();//耗时任务},100);var LoopStart=now();heavyTask();//耗时的任务console.log('heavyTask耗时:',now()-loopStart);函数heavyTask(){ var s=now();while(now()-s 1000){ } }函数now () {返回新的Date();}//输出://heavyTask耗时:1015//第一次setTimeout回调执行等待时间:1018//第二次setTimeout回调执行等待时间:1000由于耗时任务的存在,两次setTimeout的等待事件不再是100ms!让我们描述一下发生了什么:

首先,第一个耗时的任务(heavyTask())开始执行,大约需要1000毫秒才能完成。100ms后,预计会执行第一个setTimeout的回调函数,因此将其添加到事件队列中。但是前一个耗时的任务还没有执行,所以只能在队列中等待,直到耗时的任务执行完毕。因此,我们可以看到第一个setTimeout回调执行等待时间是1018。一旦执行了第一个setTimeout回调,第二个setTimeout就会启动。这个定时器也是一个回调函数,可以在延迟100毫秒后执行。然而,在第一个setTimeout中还有另一个耗时的任务,它的所有图都像第一个计时器一样,等待1000毫秒后才开始执行。可以用下图来概括:

让我们看一个setInterval的例子:

var intervalStart=now();setinterval(function(){ console . log('间隔和定义计时器之间的时间:',now()-loopStart);}, 100);var LoopStart=now();heavyTask();Console.log('heavyTask需要时间:',now()-loopStart);函数heavyTask(){ var s=now();while(now()-s 1000){ } }函数now () {返回新的Date();}//输出://heavyTask花费的时间:1013//来自定义的计时器的间隔时间:1016//来自定义的计时器的间隔时间:1123//来自定义的计时器的间隔时间:1224在上面的代码中,我们期望每100毫秒打印一次日志。与setTimeout相比,setInterval在准备向事件队列中添加回调函数时,会判断队列中是否有未执行的回调,如果有,则不会向队列中添加回调函数。否则,将同时执行多个回调。

可以用下图来概括:

摘要

本文简要分析了javascript定时器执行的原理,希望能帮助我们更深入地理解javascript。文中有一些不恰当的描述,可以在评论中指出。

更多资讯
游戏推荐
更多+