一次搞懂浏览器的EventLoop
什么是EventLoop?
EventLoop即事件循环,是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。
浏览器中的EventLoop是由 主线程、执行栈和队列共同构成。其中执行栈中的代码是提供给主线程调用的,而队列里面的代码是等待放入执行栈中的。将队列中的代码放到执行栈再被主线程执行的过程就是Event Loop。
任务执行的过程当然是有先后顺序的,主要分为两种:宏任务、微任务。
宏任务和微任务
宏任务(macrotask):script、setTimeout、setInterval、I/O、UI 交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境) 简而言之浏览器的api就是宏任务
微任务(microtask):Promise.then、 MutationObserver、 process.nextTick(Node.js 环境)简而言之js的api就是微任务
js的事件循环
我们都知道 js是单线程的,只有当上一个任务完成之后才会继续完成下一个任务,如果前一个任务耗时很长,后一个任务就不得不一直等着,于是,所有任务可以分成两种:同步任务和 异步任务。
主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为事件循环。
执行栈在执行完同步任务后,查看执行栈是否为空,如果执行栈为空,就会去执行Task(宏任务),每次宏任务执行完毕后,检查微任务(microTask)队列是否为空,如果不为空的话,会按照先入先出的规则全部执行完微任务(microTask)后,设置微任务(microTask)队列为null,然后再执行宏任务,如此循环。
好啦,总结一下大致是这样的:
所有同步任务都在主线程上执行,形成一个执行栈 (Execution Context Stack)。
而异步任务会被放置到 Task Table,也就是上图中的异步处理模块,当异步任务有了运行结果,就将该函数移入任务队列。
一旦执行栈中的所有同步任务执行完毕,引擎就会读取任务队列,然后将任务队列中的第一个任务压入执行栈中运行。
主线程不断重复第三步,也就是 只要主线程空了,就会去读取任务队列,该过程不断重复,这就是所谓的 事件循环。