对JS稍微了解一点的,应该的都知道事件机制。
更了解一点的,可能还知道事件分为宏任务和微任务。
但是事件如何而来?任务从何而来?又如何调配呢?
为什么有事件
这是个基础问题,应该大家都知道。
但是,事件机制其实是浏览器提供的,并不是JS提供的。
这里要说明一下,JS和浏览器的关系。
1.浏览器是多进程的.浏览器渲染一个网页,一般要开启一个主进程,一个渲染进程,一个网络进程,插件进程等。
2. JS是脚本语言,需要被解释执行。JS解析引擎,比如V8,是运行在渲染进程中的。
3. JS产生任务,浏览器在主线程中进行任务循环和执行。
宏事件和微事件是怎么添加的
宏任务的类型很多,定时器,网络,onload事件,鼠标事件等。
微任务常见的只有两个,Promise.then和DOM的变化。
这里重点说一下Promise.then
const test =new Promise(res,reject=>{
console.log("start")
res()
})
test.then(res=>{console.log("then")})
以上的代码中,
console.log("start") 是同步的,而console.log("then")才会被作为微任务添加到事件队列中。
微任务和宏任务是添加在不同的事件队列中的。
任务是如何调度的
微任务和宏任务是怎么分配优先级的? 任务执行有两个大原则
- 一次性只执行一个任务
- 一个任务在执行的时候,是不能被打断的。不管是微任务还是宏任务。
我们看一个《JS忍者秘籍》中给的图
1.事件循环先从宏任务队列中取出一个事件
2.宏任务执行完毕之后,去微任务队列中取出事件
3. 注意,此时不是只执行一个微任务,而是会把微任务列表中所有的任务都执行完毕。
4. 微任务队列被清空之后,进行渲染。
5. 渲染更新后,回进行下一次循环。
事件与浏览器渲染
浏览器的页面刷新一般是16ms刷新一次,微任务要求在渲染之前全部执行完毕。
我们还是参考上图。
假如页面已完成了一次刷新,那么下一次16ms毫秒就会进行第二次刷新。
浏览器执行完微任务,只用了12ms,那么就会进行下一次循环,而不会直接渲染。
如果16ms时,微任务还未完成,那么回等待微任务完成才刷新。