对于非科班计算机毕业的童鞋来说。事件循环就像一个,怎么都不太能搞清的东西。今天我用自己理解的方式,带着问题聊聊。
js为什么设计为单线程?
- js设计之初,希望能动态增删改查浏览器的dom节点。对元素做动态更改。
- 如果js是多线程的,那么,任何时候,都可以共同操作同一个元素。
- 对于浏览器来说,它并不清楚需要怎样操作,也不清楚需要先执行什么。而且,js没有事务,也不能加锁......
- 为了避免这些繁琐的操作判断,将它设计为单线程。一步操作完成,才能进行下一步。
代码的执行顺序?
- 在js的世界之初。众所周知,js执行代码的顺序,是从上置下,一行执行完成才能执行下一行代码。
- 开心写代码的时候,发现逐行执行不能满足所有的情况。如:间隔固定时间让程序做什么事情;间隔固定时间,不发出停止指令的情况下,程序做某个事情;等待固定的信号后,程序做某些事情。。。等等等。
- 在基础的从上置下不能满足的情况下,js就自己想了个办法,用了个小本本去记录,需要让它去做的事情。做完固定的事情之后,它会自动去看本子上还有没自己要做的事情,还有没有超时。
- 这样形成一个js的事件循环。
如何更好的理解事件循环?
- 打角色游戏的时候,总有一些任务需要去完成。玩家的基本操作,都是去完成主线,支线,副本的任务。
- 那么从游戏的角度来看。从上置下执行的代码,更像是
主线任务
的宏任务
。其他也需要完成,但是优先级并没有那么高的,就像是支线任务
的微任务
。 - 每次游戏,基本上都是先完成
主线任务
,在去做支线任务
。像不像宏任务
完成之后,去看微任务
队列是否存在微任务。 - 最终完整的事件流程,就变成了:
- 执行
script
同步代码(script也属于宏任务) - 执行栈为空,查询是否有微任务需要执行
- 执行所有的微任务
- 必要的话渲染UI
- 然后开始下一轮
Event loop
,执行宏任务中的异步代码
- 执行
事件循环的误区
setTimeout
事件值设置为0
,与promise
代码,谁先执行?setTimeout( ()=>{ console.log('set'); },0); new Promise( (r,i) => { console.log('p1'); r('r1'); }).then((r)=>{console.log(r)})
- 结果是什么?
- 代码从上往下执行,遇到
setTimeout
,用小本本记到宏任务,遇到Promise
,输出p1
,其他的用小本本记到微任务里了。 - 代码从上置下执行完成,去微任务队列查看是否有任务,输出
r1
- 继续执行宏任务异步代码
setTimeout
,输出set
- 就是这么简单。
宏任务,微任务队员归类
- 宏任务
script
setTimeout
setInterval
- 微任务
process.nextTick
promise
Object.observe
MutationObserver