原文:做一些动图,学习一下EventLoop (https://juejin.cn/post/6969028296893792286)
一、任务队列
JavaScript 是单线程执行的语言, 在同一时间只能干一件事情。如果前面的任务很耗时后面的任务就会一直等待,为了解决这个问题,js中出现了同步任务和异步任务
1.1 同步任务
在主线程上排队执行的任务只有前面执行完毕才能执行下一个任务,形成一个执行栈
1.2 异步任务
不进入主线程,而是进入任务队列,只有当主线程的任务执行完毕,才会从任务队列中拿任务到主线程来执行。由于主线程不断循环 获取任务 -> 执行任务 -> 再次获取任务 -> 再次执行任务
,所以这种机制被叫做 事件循环
。
二、宏任务和微任务
在任务队列中其实还分为宏任务队列和微任务队列,里面存放的就是宏任务和微任务
宏任务和微任务都是异步任务, 这两者的区别就是它们的执行顺序。
在同步任务中, 任务都是讲究按照代码顺序执行的, 而异步任务也是需要按照顺序执行的; 队列的属性就说先进先出, 因此异步任务会按照进入队列的顺序以此执行。
这就解释了为什么下列代码中,为什么后面的定时器比前面的定时器先执行。因为后者的定时器先推进宏任务队列,而前者会在到时间后再被推进宏任务队列
setTimeout(() => {
console.log('a');
}, 10000);
setTimeout(() => {
console.log('b');
}, 100);
2.1 宏任务
宏任务包括:script(整体代码)
, setTimeout
, setInterval
, Ajax
, DOM事件
, requestAnimationFrame ( 只存在浏览器中 )
, I/O
, SetImmediate( node )
2.2 微任务
微任务包括:Promise.then
, async/await
, Object.observe ( 已废弃 )
, MutationObserver ( HTML5新特性, 只存在浏览器中 )
, process.nextTick ( node )
三、完整的执行顺序
- 从上往下执行所有的同步代码
- 在执行过程中遇到宏任务就存放到宏任务队列中, 遇到微任务就存放到微任务队列中
- 当所有的同步任务执行完毕, 就执行微任务队列中满足需求的所有回调
- 当微任务队列中所有满足需求的回调执行完毕后, 就执行宏任务队列中满足需求的所有回调
3.1 注意
每执行完一个宏任务都会立即检查微任务列表有没有清空, 如果没有就立即清空。
Promise里的是同步任务,立即执行