微任务、宏任务、事件循环、异步
微任务、宏任务、事件循环、异步
这一部分主要讲述了 JavaScript 的执行,涉及到的知识点
- 事件循环
- 微任务宏任务
- 异步执行
- async 和 generator 对比
事件循环(Event Loop)
事件循环包含的知识点很多。而且浏览器和 NodeJS 的事件循环还略有不同。
浏览器的 Event Loop
浏览器的事件循环和 NodeJs 的事件循环不同。
JavaScript 是单线程的,因此同一个时间只能做一件事。JavaScript 作为浏览器语言,如果采用多线程可能会带来一些复杂的同步问题,比如两个线程操作 DOM,一个修改,一个删除,不太好判断此时的交互状态。JavaScript 主要用途是和用户互动,操作 DOM。
单线程意味着需要排队,如果前一个任务时间很长,后面的任务就会被阻塞。IO(比如 Ajax)很慢,如果一直等待会造成 CPU 空闲(操作系统中的多道批处理操作系统)。浏览器和服务端不同。浏览器端受限于网络原因,网络不好的情况下,请求可能会很长时间才会响应。因此对于浏览器端来讲,更合理的方案是异步(CommonJs 和 AMD&CMD 方案原因同)。
对任务来讲,可以分为同步任务和异步任务。同步任务进入主线程,按顺序执行。异步任务不进入主线程,进入”任务队列”,只有异步任务有运行结果了,就会在”任务队列”中放置事件。主线程上的同步任务执行完毕后,才会读取”任务队列”,异步任务才会进入执行栈,开始执行(执行异步任务的回调函数)。
说到事件循环,就要提到定时器的问题(setTimeout 和 setInterval)。定时器进入”执行队列”,因此会等待执行栈内的任务执行完毕后才会执行,如下代码。执行顺序是 1 2。
1 | setTimeout(function () { |
这样就会产生一个问题,函数设置的执行时间未必一定会执行,设置的时间只是到目标时间时将其放入”任务队列”,如果执行找还有任务,那么就不会执行。如下,5s 后才会执行,并不是 1s。
1 | setTimeout(function () { |
NodeJS 的 Event Loop
NodeJS 提供了process.nextTick
和setImmediate
两个与”任务队列”相关的方法。
- process.nextTick:在”执行栈”的尾部触发回调(发生在所有异步任务之前)
- setImmediate:在”任务队列”尾部触发回调(下一次 Event Loop 开始时执行)
执行宏任务的几个队列。
- timers 阶段:执行 setTimeout,setInterval 回调
- I/O callbacks 阶段:其它异步回调
- idle,prepare 阶段:node 内部使用
- poll 阶段:获取新的 I/O 事件
- check 阶段:执行 setImmediate 回调
- close callbacks 阶段:执行 socket.on(‘close’, …)等回调
执行微任务的几个队列。
- Next Tick 队列:放置 process.nextTick 回调
- Other Micro 队列:放置其它微任务,比如 Promise
微任务、宏任务
首先,微任务和宏任务的概念来区。一个 JavaScript 引擎会常驻内存中,等待我们(宿主)把 JavaScript 代码或函数传递执行。
在之前,JavaScript 本身还没有异步执行代码的能力,就意味着宿主传递给 JavaScript 引擎一段代码,引擎直接把代码顺序执行了,这个任务就是宿主发起的任务。在 ES6 引入的 Promise,不需要浏览器的安排,JavaScript 引擎本身也能发起任务了。
- 宏任务:这里把宿主发起的任务称为宏任务(setTimeout,setInterval)
- 微任务:JavaScript 引擎发起的任务称为微任务(Promise)
总结一下,浏览器端的循环优先级,在同一个循环下,同步 > 微任务(Promise) > 宏任务(setTimeout,setInterval)
Generator 和 async
这里感觉 winter 和阮一峰两者对其区别的解释似乎有一些出入。
winter:
generator 并非被设计成实现异步,所以有了 async/await 之后,generator/iterator 来模拟异步方法应该被废弃。
阮一峰:
Generator 函数是 ES6 提供的一种异步编程解决方案。async 函数是什么?一句话,它就是 Generator 函数的语法糖。
两者似乎是有些不同,但是根据我重新阅读 Generator 后,我个人更偏向于 winter 的解释,Generator 里的 co 模块就是用于函数的自动执行,此时才算是模拟了 async/await。
那 Generator 的适用范围?根据我的理解,和状态机比较的契合,刚好在做 html 解析的部分,可以尝试用 Generator 来写一写。
- 感谢你的欣赏!