同步任务、异步任务
JavaScript是一门单线程语言,分为同步任务和异步任务
同步任务
在主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务。
异步任务
- 不进入主线程、而进入"任务队列"的任务
- 只有等主线程任务全部执行完毕,"任务队列"的任务才会进入主线程执行。
- 异步任务分为宏任务和微任务
- 宏任务:宿主(Node、浏览器)发起的,会触发新一轮Tick的事件
- 比如:script (可以理解为外层同步代码)、定时器回调、UI rendering/UI事件、postMessage,MessageChannel 、setImmediate,I/O(Node.js)、DOM 事件回调、ajax 回调
- 微任务:JS引擎发起的事件
- 比如:promise的回调、MutationObserver 的回调、object.observe(已废弃;Proxy 对象替代) 4. process.nextTick(Node.js)
- 宏队列、微队列:js 中用来存储待执行回调函数的队列包含 2 个不同特定的列队
- 宏队列:用来保存待执行的宏任务(回调)
- 微队列:用来保存待执行的微任务(回调)
执行顺序(即事件循环)
- 先执行所有同步任务,碰到异步任务放到任务队列中
- 同步任务执行完毕,开始执行当前所有的异步任务
- 先执行微队列里面所有的微任务
- 设置进入微任务检查点的标志为true。
- 当事件循环的微队列不为空时:
- 选择一个最先进入microtask队列的microtask;
- 设置事件循环的当前运行任务为已选择的microtask;
- 运行microtask;
- 设置事件循环的当前运行任务为null;
- 将运行结束 的microtask从microtask队列中移除。
- 对于相应事件循环的每个环境设置对象(environment settings object),通知它们哪些promise为 rejected。
- 清理indexedDB的事务。
- 设置进入microtask检查点的标志为false。
- 更新界面渲染。
- 然后执行一个宏任务,如果没有宏任务可以选择,则会 跳转至微任务的执行步骤。
- 将事件循环的当前运行宏任务设置为已选择的宏任务。
- 运行宏任务。
- 将事件循环的当前运行任务设置为null。
- 将运行完的宏任务从宏任务队列中移除。
- 然后再执行所有的微任务
- 再执行一个宏任务,再执行所有的微任务·······依次类推到执行结束。
当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件, 然后再去宏任务队列中取出一个 事件。同一次事件循环中, 微任务永远在宏任务之前执行。