浏览器探究之事件循环(4)

284 阅读3分钟

这是我参与更文挑战的第9天,活动详情查看:更文挑战


众所周知,JavaScript是单线程语言,这是它本身的特性决定的。这个特性保证了它可以很好地处理用户交互、DOM操作等问题。但同时它还具备了多任务交替处理的能力,这个能力就是通过事件循环(Event Loop)来实现的。

刚刚想到一个合适的比方,就是去医院看病。

医生只有一个,一次只能接待一位病人。(单线程)

病人们需要排队等医生叫号。(执行栈,此处稍不符合的是例子属于队列,但不影响)

碰到普通病人,医生问诊完就解决了。(同步任务直接执行)

碰到需要做检查的病人,医生会先开个单子安排检查,并嘱咐检查完再回来继续看。(异步任务指定单独的线程去处理,处理完后执行回调)

做完检查的病人,重新来到医生这里另外排一个复诊队伍,等待医生看完初诊的队伍再来看他们。(执行栈空了之后检查任务队列)

复诊的队伍也排了两个:一个医生说做完检查「立即来等」的,第二个是医生说做完检查过一个小时以后再回来等的。(微任务和宏任务)

医生把今天挂号的队伍都看完之后,先把「立即来等」的队伍一个一个看完,再去看「过段时间来等」的队伍有没有人,有人的话就叫一个进来,中间一旦「立即来等」的队伍来了新人,就安排优先进来看。

现在再来了解以下概念:

执行栈(execution context stack)与任务队列(task queue)

按照这样的标准,JavaScript中的任务分为了同步和异步两种:

  • 同步任务:在主线程上排队执行的任务,按顺序一个一个执行,形成一个执行栈。
  • 异步任务:不进入主线程,而进入任务队列排队的任务。异步任务有了运行结果,就在任务队列中放置一个事件,一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列中的任务开始执行。

宏任务和微任务

任务队列中又分为两种:宏任务和微任务。 以下事件属于宏任务:

setInterval() setTimeout() 以下事件属于微任务

new Promise() new MutaionObserver()

  • 宏任务 (macro tasks): script(全局任务) 、setTimeout、setInterval、setImmediate、I/O、UI rendering

  • 微任务(micro tasks):process.nextTick、Promise.then、Object.observer、MutationObserver

循环机制

主线程不断重复这个过程,就是事件循环(Event Loop)。

事件循环中,从任务队列中取任务执行的步骤:

  1. 取一个宏任务来执行,执行完毕进入下一步;

  2. 取一个微任务来执行,执行完再取一个微任务执行,直到微任务执行完,再进行下一步;

  3. 更新UI.

以上三步会循环执行。

image.png

image.png