为什么会有事件循环和任务队列
JS是单线程,即同一时间只能做一件事情;为什么是单线程呢?
JavaScript的单线程,与它的用途有关。
作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。
这决定了它只能是单线程,否则会带来很复杂的同步问题。为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JS脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JS单线程的本质。
比如,假定JavaScript同时有两个线程,
一个线程在某个DOM节点上添加内容,
另一个线程删除了这个节点,
这时浏览器应该以哪个线程为准?
所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。
任务队列
什么是任务队列?
既然JS是单线程,那就意味着所有任务只能排队一个一个的执行
万一某个任务耗时很长,那后面的只能一直等前面执行完才能继续执行。CPU忙不过来,倒也算了,但是很多时候CPU是闲着的
JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。
于是,所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入”任务队列”(task queue)的任务,只有”任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
任务分类
所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。
异步任务又可以分为两种:
宏任务:script, setTimeout, setInterval, setImmeditate, T/O, UI rendering
微任务:process, nextTick, promise.then(), object.observe, MutationObserver
运行机制
- 所有的同步任务都在主线程的执行栈中就行执行
- 除了主线程之外还有一个任务队列 ,只有异步返回运行结果,就在任务队列放置一个事件
- 执行栈中的同步任务执行完后,将任务队列中返回结果的异步任务放置执行栈中执行
执行顺序
-
先执行主线程
-
遇到宏队列(macrotask)放到宏队列(macrotask)
-
遇到微队列(microtask)放到微队列(microtask)
-
主线程执行完毕
-
执行微队列(microtask) 判断微任务队列是否存在异步任务,若存在的话执行2和3 微队列(microtask)执行完毕
-
执行一次宏队列(macrotask)中的一个任务 判断宏任务队列是否存在异步任务,若存在的话执行2和3 宏队列(microtask)执行完毕
-
执行微队列(microtask),执行完毕
-
依次循环。。。