通过一个JS动画了解JS中的EventLoop

前言
上一篇文章我们说了如何实现一个Promise
,这次我们就通过一个JS 动画了解一下什么是EventLoop。
一个 JS 动画
这次需要实现的动画是一个通过 JS 向前端页面添加文本和样式的动画。最终的效果如下图:
调用代码
根据实现结果和调用代码,可以想到的实现思路是:
- 通过链式调用将数据的向前端一行一行地输出。
- 主要通过
text
和style
两个方法向前端输出 - 输出的每一行都可以有时间控制
- 通过
setTimeout
向前端输出文字
基本思路已经有了,下面就开始码吧~~
1.创建 Animate 类
- 首先需要创建一个 Animate 的方法,在调用时初始化信息
- 实例化的时候需要传两个参数,
head
的 element 标签和body
的 element 标签 - 初始化信息包括创建三个 HTML 标签,分别是
输出的信息的box
,输出style的box
和更新样式的style标签
1 | class Animate { |
调用后我们需要用来展示和改变样式的节点都已经创建完成了,接下来需要实现往text_content
中添加信息
2.往 text 中添加信息
- 上面已经说了,我们需要用
setInterval
往内容盒子中添加信息,并且将总输出时间为用户输出的时间,那就需要计算输出每一个字的间隔时间,公式也很简单输出字体间隔时间 = 输出总时间 / 文字总长度
。
在Animate
类中添加text
方法,输出文字的公共方法,还有一个输出字体间隔时间的方法
1 | /** |
调用animate.text
后可以看到他已经可以输出啦:
3.EventLoop(事件循环机制)
我们的Animate
写到这里,它的最基础的输出文字功能已经实现啦。接下来需要实现的是让每一段文字按顺序输出,要实现按顺序地输出必须要让每一个输出方法按顺序地执行。但是 JavaScript 它不会让我们实现的方法轻易地得逞~
测试一下:
1 | // 测试 |
输出:
我们理想的状态应该是每一个text
都按顺序执行,而不是同时执行。这时因为 Javascript 是单线程的,所以 JS 在执行的时候会有一个执行队列(先进先出),它将所有要执行任务放到执行队列中按序执行,但执行任务又是什么?
JS 中执行任务分为两种:宏任务(macrotask)和微任务(microtask),他们在 JS 中的执行顺序是:先执行宏任务后执行微任务。
- 宏任务有:script,setInterval,setTimeout,I/O,requestAnimationFrame,setImmediate(Node.js)
- 微任务有:Promise.then,MutationObserver,process.nextTick(Node.js)
了解完执行队列,再来看一下刚刚写的测试例子。当调用animate.text
时,因输出文字方法中有setInterval
,setInterval
不会先执行,而是插入到任务队列
中,如下图
当三个animate.text
执行完后,任务队列添加了三个setInterval
宏任务,当 script 的方法执行完后,第一插入的setInterval
开始执行并输出H
,然后在指定的时间往任务队列最后面添加插入宏任务(因为setInterval
一个循环执行的方法,每隔一段时间会执行,直到计时器被清除)
了解完 JS 的执行队列,回到动画代码中,我们需要怎样才能实现一个一个text
方法按顺序执行。
上一篇文章在实现 Promise 的时候,使用了两个运行队列(resolveArr,rejectArr)来装等待状态改变时执行的方法。这里同样也可以这样做,在类的构造器中添加一个函数数组,将所有执行时的方法在script
宏任务执行时就添加到数组中,script
中的代码执行完后再新建一个宏任务去一个一个执行数组中的方法。
接下来要:
- 往构造器中添加一个函数数组
- 添加一个执行函数数组的
run
方法 - 添加一个宏任务去执行
run
- 将
text
方法中执行的代码放到函数数组中,每次执行完后都调用run
方法去执行函数数组中的下一个方法 - 修改
printText
方法为 Promise 方法
1 | constructor() { |
修改完后我们再来调用刚刚的测试例子
1 | // 测试 |
成功了!现在再来看一下它的执行队列图:
4.最后添加 style 和链式调用
到这里我们的方法已经可以实现按顺序向界面输出文字了,最后需要做的是添加style
和链式调用
,添加style
的实现方法和添加文字大致是相同的,链式调用其实就是在每个方法执行后 return 这个对象本身就可以了,这里就不多做解释啦,最终的代码:
1 | ; |
测试:
1 | ; |
小结
- 源码地址
- 我们通过一个动画的例子来了解了 JS事件循环的执行机制,代码在浏览器/node 中是如何执行的。
- 宏任务:script,setInterval,setTimeout,I/O,requestAnimationFrame,setImmediate(Node.js)
- 微任务:Promise.then,MutationObserver,process.nextTick(Node.js)
- 先执行宏任务,后执行微任务
- 最后,通过这一个小动画例子我们可以利用代码给自己做一个好玩的东西,例如:自动展示的简历 😁