视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
关于JavaScript中定时器的原理解析
2020-11-27 20:11:15 责编:小采
文档
 在我们工作中很多人说到javascript中的定时器都会想到setTimeout() 和 setInterval() 这两个函数,但是却不知道JavaScript中定时器的原理是什么,那么本文将从事件循环(Event Loop) 的角度来分析定时器函数的工作原理和区别!

setTimeout()

MDN对 setTimeout 的定义为:

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

语法

setTimeout 的语法非常简单,第一个参数为回调函数,第二个参数为延时的时间。函数返回一个数值类型的ID唯一标示符,此ID可以用作 clearTimeout 的参数来取消定时器:

IE0+ 还支持回调参数的传入:

setInterval()

MDN 对 setInterval 的定义为:

周期性地调用一个函数(function)或者执行一段代码。

由于 setInterval 和 setTimeout 的用法一样,所以这里不再列出。

对第二个参数(delay)的说明

由于javascript 的事件循环机制,导致第二个参数并不代表延迟delay毫秒之后立即执行回调函数,而是尝试将回调函数加入到事件队列。实际上,setTimeout 和 setInterval 在这一点上处理又存在区别:

  • setTimeout:延时delay毫秒之后,啥也不管,直接将回调函数加入事件队列。

  • setInterval: 延时delay毫秒之后,先看看事件队列中是否存在还没有执行的回调函数(setInterval的回调函数),如果存在,就不要再往事件队列里加入回调函数了。

  • 所以,当我们的代码中存在耗时的任务时,定时器并不会表现的如我们所想的那样。

    通过一个例子来理解

    下面的代码,本来希望能够在 100ms 和 200ms 的时候(也就是刚好等待 100ms)调用回调函数:

    输出:
    // 第一个setTimeout回调执行等待时间: 106
    // 第二个setTimeout回调执行等待时间: 107

    这样的结果看上去正是我们所想的那样,但是一旦我们在代码中加入了耗时的任务时候,结果就不像我们所期望的那样了:

    输出:
    // heavyTask耗费时间: 1015
    // 第一个setTimeout回调执行等待时间: 1018
    // 第二个setTimeout回调执行等待时间: 1000

    两个 setTimeout 的等待事件由于耗时任务的存在不再是 100ms 了!我们来描述一下事情的经过:

    1. 首先,第一个耗时任务(heavyTask())开始执行,它需要大约 1000ms 才能执行完毕。

    2. 从耗时任务开始执行,过了 100ms, 第一个 setTimeout 的回调函数期望执行,于是被加入到事件队列,但是此时前面的耗时任务还没执行完,所以它只能在队列中等待,直到耗时任务执行完毕它才开始执行,所以结果中我们开的看到的是: 第一个setTimeout回调执行等待时间: 1018。

    3. 第一个 setTimeout 回调一执行,又开启了第二个 setTimeout, 这个定时器也是期望延时 100ms 之后能够执行它的回调函数。 但是,在第一个 setTimeout 又存在一个耗时任务,所有它的剧情跟第一个定时器一样,也等待了 1000ms 才开始执行。

    可以用下面的图来概括:

    再来看 setInterval 的一个例子:

    输出:
    // heavyTask耗费时间: 1013
    // interval距定义定时器的时间: 1016
    // interval距定义定时器的时间: 1123
    // interval距定义定时器的时间: 1224

    上面这段代码,我们期望每隔 100ms 就打出一条日志。相对于 setTimeout 的区别, setInterval 在准备把回调函数加入到事件队列的时候,会判断队列中是否还有未执行的回调,如果有的话,它就不会再往队列中添加回调函数。 不然,会出现多个回调同时执行的情况。

    可以用下面的图来概括:

    总结:

    上面对javascript定时器执行原理进行了简要的分析,相信小伙伴们对JavaScript定时器的工作原理有了一定的认识了,希望能够帮助你。

    相关推荐:

    Javascript定时器实例代码

    深入探寻javascript定时器

    javascript定时器完整实例

    JavaScript定时器和优化的取消定时器方法

    下载本文
    显示全文
    专题