JS忍者秘籍中的定时器机制详解

简介: 前言前段时间刚看完《JS忍者秘籍》,虽说是15年出版的,有些东西是过时了,但像对原型链、闭包、正则、定时器之类的机制却是不会过时的,里面很多东西都讲的很细,还是值得一读的,本文将对这本书中对定时器机制的部分进行详细的解析,如果喜欢的话可以点波赞/关注,支持一下,希望大家看完本文可以有所收获。个人博客了解一下:obkoro1.com准备阅读本文之前,推荐先阅读Js 的事件循环(Event Loop)机制以及实例讲解这篇文章来理解背后发生的事情,本文对事件循环机制不会很仔细的讲解。定时器解决的问题:由于JS的单线程特性,定时器提供了一种跳出单线程限制的方法。

image.png

前言

前段时间刚看完《JS忍者秘籍》,虽说是15年出版的,有些东西是过时了,但像对原型链、闭包、正则、定时器之类的机制却是不会过时的,里面很多东西都讲的很细,还是值得一读的,本文将对这本书中对定时器机制的部分进行详细的解析,如果喜欢的话可以点波赞/关注,支持一下,希望大家看完本文可以有所收获。


准备

阅读本文之前,推荐先阅读Js 的事件循环(Event Loop)机制以及实例讲解这篇文章来理解背后发生的事情,本文对事件循环机制不会很仔细的讲解。

定时器解决的问题:

由于JS的单线程特性,定时器提供了一种跳出单线程限制的方法,即让一段代码在一定毫秒之后,再异步执行。

设置和清除定时器:

直接引用忍者秘籍中的图片:

image.png

注意:

  1. 定时器的时间间隔设为0,也会有几毫秒的延迟。
  2. 在使用setTimeoutsetInterval的时候最好将其赋值给一个变量,以便取消定时器。
  3. 在使用Vue的时候,setTimeoutsetInterval的this指向的是window对象,访问不到组件数据以及方法。
  4. 在使用Vue的时候,路由跳转并不会销毁setInterval,但是组件已经销毁了,这会导致问题。
  5. 在执行线程中setTimeout/setInterval无法保证准时执行回调函数的。
  6. setInterval调用有可能会被废弃以及setInterval的连续执行

第三点和第四点的解决方法可以参考我之前写的Vue 实践过程中的几个问题

接下来要讲的是第五点和第六点,这两点是最重要,也是本文要重点解析的内容。

执行线程中的定时器执行

下面来看忍者秘籍中的栗子:

image.png

让我们看看这里发生了什么事情:

  1. 首先在0毫秒的时候有一个持续18毫秒的js代码块要执行。
  2. 然后在0毫秒的时候设了两个10毫秒延迟的定时器,setTimeout以及setInterval,setTimeout先设定。
  3. 在第6毫秒的时候有一个发生了鼠标单击事件。

事件排队。

同时发生了这么多事情,由于js的单线程特性,当线程正在执行状态,有异步事件触发时,它就会排队,并且在线程空闲时才进行执行

这里的异步事件包括:鼠标单击,定时器触发,ajax请求、promise等事件。

让我们回到栗子中:

栗子中首先有一个18毫秒的代码块要执行,在这18毫秒中只能执行这段代码块,其他事件触发了之后只能排队等待执行

在代码块还在运行期间,第6毫秒的时候,发生了一个鼠标单击事件,以及第10毫秒时的setTimeoutsetInterval两个处理程序,这三个事件不能立即执行,而是被添加到等待执行的队列中。

先进先出(先排队的先执行)

18毫秒的时候代码块结束执行,有三个任务在排队等待执行,根据先进先出的原则,此时会先执行click事件setTimeoutsetInterval将继续排队等待执行。

setInterval调用被废弃

在click事件执行时,第20毫秒处,第二个setInterval也到期了,因为此时已经click事件占用了线程,所以setInterval还是不能被执行,并且因为此时队列中已经有一个setInterval正在排队等待执行,所以这一次的setInterval的调用将被废弃

浏览器不会对同一个setInterval处理程序多次添加到待执行队列。

setTimeout/setInterval无法保证准时执行回调函数

click事件在第28毫秒处结束执行,有两个任务(setTimeoutsetInterval)正在等待执行,遵循先进先出的原则,setTimeout早于setInterval设定,所以先执行setTimeout

so:我们期望在第10毫秒处执行的setTimeout处理程序,最终会在第28毫秒处才开始执行,这就是上文提到的setTimeout/setInterval无法保证准时执行回调函数。

在30毫秒处,setInterval又触发了,因为队列中已经有setInterval在排队,所以这次的触发又作废了。

setInterval的连续执行

setTimeout执行结束,在第36毫秒处,队列中的setInterval处理程序才开始执行,setInterval需要执行6毫秒。

在第40毫秒的时候setInterval再次触发,因为此时上一个setInterval正在执行期间,队列中并没有setInterval在排队,这次触发的setInterval将进入队列等候

所以:setInterval的处理时长不能比设定的间隔长,否则setInterval将会没有间隔的重复执行

第42毫秒的时候,第一个setInterval结束,然后队列中的setInterval立即开始执行,在48毫秒的时候完成执行。然后50毫秒的时候再次触发setInterval,此时没有任务在排队,将会立即执行。

setTimeout按照一定的间隔周期性的触发定时器。

上文说了,setInterval的处理时长不能比设定的间隔长,否则setInterval将会没有间隔的重复执行

但是对这个问题,很多情况下,我们并不能清晰的把控处理程序所消耗的时长,为了我们能按照一定的间隔周期性的触发定时器,忍者秘籍中提供了下面这种使用方法:

// 实际上我不止在忍者秘籍中见过,在很多地方都见过这种技术。
    setTimeout(function repeatMe(){
      // do something
      setTimeout(repeatMe,10); 
      // 执行完处理程序的内容后,在末尾再间隔10毫秒来调用该程序,这样就能保证一定是10毫秒的周期调用
    },10)

忍者秘籍中关于定时器的其他知识:

  • 定时器不能非常细粒化的控制执行的时间,书中建议在15ms以上。
  • 可以使用定时器来分解长时间运行的任务,这里可以自行谷歌。

任务队列只有排队这么简单吗?

事实上,关于任务队列并不是只有简单的排队而已,忍者秘籍中提到为了方便,使用了这个概念,如果希望能更清晰的了解背后的机制,再次推荐阅读一下:Js 的事件循环(Event Loop)机制以及实例讲解


结语

这上面所有一切,都是由js单线程特性导致的,所以会有事件排队、先进先出、setInterval调用被废弃、定时器无法保证准时执行回调函数以及出现setInterval的连续执行,时刻记住这一特性,很多关于事件执行顺序的问题都能想的通,并且找出解决方法。


目录
相关文章
|
1月前
|
JavaScript 前端开发 安全
JavaScript基础-定时器:setTimeout, setInterval
【6月更文挑战第13天】JavaScript中的`setTimeout`和`setInterval`是异步编程的关键工具,用于按计划执行代码。`setTimeout`在延迟后执行一次,而`setInterval`则周期性执行。常见问题包括忘记清除定时器导致内存泄漏,递归使用`setTimeout`可能引发无限递归,以及字符串代码执行的安全隐患。解决方法包括使用`clearTimeout`和`clearInterval`,设置递归终止条件,以及优先使用函数表达式。理解定时器的非精确性并采用错误处理策略也是实践中的重要技巧。通过示例展示了如何延迟显示消息和周期性打印计数。
|
2月前
|
前端开发 JavaScript UED
深入理解JavaScript中的事件循环机制
JavaScript中的事件循环机制是其异步编程的核心,深入理解该机制对于开发高效、流畅的前端应用至关重要。本文将介绍事件循环的工作原理、常见的事件循环模型,以及如何利用这些知识解决前端开发中的常见问题。
|
26天前
|
设计模式 JavaScript 前端开发
【JavaScript】深入浅出JavaScript继承机制:解密原型、原型链与面向对象实战攻略
JavaScript的继承机制基于原型链,它定义了对象属性和方法的查找规则。每个对象都有一个原型,通过原型链,对象能访问到构造函数原型上的方法。例如`Animal.prototype`上的`speak`方法可被`Animal`实例访问。原型链的尽头是`Object.prototype`,其`[[Prototype]]`为`null`。继承方式包括原型链继承(通过`Object.create`)、构造函数继承(使用`call`或`apply`)和组合继承(结合两者)。ES6的`class`语法是语法糖,但底层仍基于原型。继承选择应根据需求,理解原型链原理对JavaScript面向对象编程至关重要
33 7
【JavaScript】深入浅出JavaScript继承机制:解密原型、原型链与面向对象实战攻略
|
13天前
|
JavaScript 前端开发
vue 模拟随机变速的动态打字特效【支持多行文本】(含css实现闪烁光标,js动态改变setInterval定时器的时间间隔)
vue 模拟随机变速的动态打字特效【支持多行文本】(含css实现闪烁光标,js动态改变setInterval定时器的时间间隔)
12 1
|
25天前
|
JavaScript 前端开发
杨老师课堂之JavaScript定时器案例的红绿灯设计
杨老师课堂之JavaScript定时器案例的红绿灯设计
22 1
|
13天前
|
JavaScript 前端开发 API
js 运行机制(含异步机制、同步任务、异步任务、宏任务、微任务、Event Loop)
js 运行机制(含异步机制、同步任务、异步任务、宏任务、微任务、Event Loop)
8 0
|
24天前
|
JavaScript 前端开发
杨校老师课堂之JavaScript定时器案例的红绿灯设计--原始写法
杨校老师课堂之JavaScript定时器案例的红绿灯设计--原始写法
10 0
|
25天前
|
JavaScript 前端开发
杨老师课堂之JavaScript定时器限时抢购秒杀商品案例
杨老师课堂之JavaScript定时器限时抢购秒杀商品案例
14 0
|
2月前
|
缓存 移动开发 JavaScript
WKWebView对网页和js,css,png等资源文件的缓存机制及如何刷新缓存
WKWebView对网页和js,css,png等资源文件的缓存机制及如何刷新缓存
53 1