JS单线程和Event Loop

JS是单线程

原因——避免DOM渲染冲突

  • 浏览器需要渲染DOM

  • JS可以修改DOM结构

  • JS执行的时候,浏览器DOM会暂停

  • 两段JS也不能同时执行(都修改DOM就冲突)

  • webworker支持多线程,但是不能访问DOM

解决方案——异步

setTimeout // 时间到了再执行
ajax // 加载完再执行

异步问题

  • 没按照书写方式执行,可读性差

  • callback中不容易模块化

实现异步的方案——Event Loop

  • 事件轮询,JS实现异步的具体解决方案

  • 同步代码,直接执行

  • 异步函数先放在异步队列中

  • 待同步函数执行完毕,轮询执行异步队列的函数

异步任务中的分类——宏任务和微任务

宏任务: script、 setTimeout、setInterval、ajax、requrestAnimationFrame
  1. 宏任务所处的队列就是宏任务队列

  2. 第一个宏任务队列中只有一个任务:执行主线程的js代码

  3. 宏任务队列可以有多个

  4. 当宏任务队列中的任务全部执行完以后会查看是否有微任务队列,如果有,先执行微任务队列中的所有任务。如果没有就查看是否有宏任务队列。

微任务: Promise().then(回调)、process.nextTick(node中)
  1. 微任务所处的队列就是微任务队列

  2. 只有一个微任务队列

  3. 在上一个宏任务队列执行完毕后如果有微任务队列就执行微任务队列中所有任务

总结:JS是单线程,同时只做一件事,原因是为了避免DOM渲染冲突。异步是一种解决方案,具体的实现就是Event Loop。同步代码直接执行,异步代码先放在异步队列中,待同步代码完毕,轮询执行异步队列中函数。

异步任务又可以分为两种,micro-tast(微任务)和macro-tast(宏任务)。

  1. 初始化状态:执行stack为空。macro-tast(宏任务)队列中只有一个script脚本。
  2. script脚本被推入执行stack,同步代码执行,执行过程可以产生新的macro-task和micro-task,并且推入各自的队列中,script脚本执行完成,则会移除任务队列。
  3. macro-task移除队列后,接着执行micro-task。
  4. 执行UI渲染操作,更新界面。
  5. 继续执行下一个宏任务

注意:macro-task是一个个执行的,而micro-task是一队一对执行。因此,处理micro会逐个执行,直至队列被清空。每个macro-task之间会进行render

拓展知识:Vue中nextTick原理

定义:在下次DOM更新循环结束之后执行的延迟回调。在修改数据之后立即使用该方法,获取更新后的DOM。
原理:Vue在更新DOM时是异步执行的。只要侦听到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个watcher被多次触发,只会被推入到队列中一次。这种缓冲时去除重复数据对于避免不必要的计算和DOM操作是非常重要的。而后,在下一个事件循环"tick"中,Vue刷新队列并执行(已去重)工作。Vue在内部对异步队列优先尝试使用微任务: Promise.then、MutationObserver和setImmediate。如果执行环境不支持,则会采用宏任务: setTimeout代替。nextTick接受一个函数,将这个函数cb的形式放到任务队列中(以微任务优先),当每次tick结束之后就会去执行这些cb。
posted @ 2020-09-09 22:30  不务正业的咸鱼  阅读(164)  评论(0)    收藏  举报