js中的任务
js是单线程异步编程:借用浏览器的多线程机制,再基于EventLoop事件循环机制,实现单线程异步效果。
| 异步微任务 | 异步宏任务 |
|---|---|
| requestAnimationFrame | setTimeout/setInterval |
| promise.then/finally/catch | 事件绑定 |
| async/await | XMLHttpRequest/Fetch请求 |
| MutationObserver | IO操作 |
| process.nextTick | script(整体代码) |
EventLoop事件循环过程
浏览器加载页面,除了开辟堆栈内存,还开辟了两个队列
- WebApi:任务监听队列:监听异步的任务是否可以执行。
- EventQueue:所有可执行的异步任务:需要在这里排队等待执行。(异步微任务/异步宏任务)
流程:
- js主线程自上而下执行代码中,遇到异步任务会把异步任务放到WebApi中进行监听。(开辟新的线程去监听,不会阻碍主线程代码的执行。)
- 当WebAp中监听任务(setTimeout)可以执行了,也不会立即执行,而是放到EventQueue任务队列中进行排队。(根据微任务/宏任务分类放在不同的任务队列中)
-
- 例如:定时器,设定一个等待时间,时间到了也不会立即执行。。。。
- 当同步代码(同步宏任务)执行完毕,主线程空闲下来之后,此时去循环执行EventQueue队列中的任务。
-
- 按照异步微任务->异步宏任务执行(每次执行一个宏任务之前都要把微任务队列执行完)
-
- 同样级别按谁先放入谁先执行
事件循环示例
- 宏任务执行流程
- Promise微任务执行流程
promise.then(onfullfilled,onrejected),回调函数先进入WebApi中,监听promise的状态是成功后,把onfullfilled放入EventQueue的微任务队列中等待执行。
console.log(1)
new Promise((resolve, reject) => {
console.log(2) // 执行器函数是同步代码
resolve("ok")
}).then(res => {
// .then是异步微任务
console.log(3)
})
console.log(4)
/* 输出
* 1 -> 2 -> 4 ->3
*/
- 遇到await
- 会立即执行await后面的代码,看返回的promise实例(不是promise实例也会变成promise实例)是否成功。
- 会把当前执行上下文中,await下面的代码当作异步微任务。放到EventQueue任务微队列中,当同步代码执行完再循环执行。
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
// 语法糖:上面的代码等价于 ==>
async function async1() {
console.log('async1 start');
Promise.resolve(async2()).then(() => {
console.log('async1 end')
})
}
- 在执行宏任务中如果产生了微任务,需要先执行完微任务队列中的所有微任务,才执行下一个宏任务。
*如有不对的地方,欢迎交流。