关于JavaScript的宏任务与微任务

120 阅读1分钟

异步

异步任务介绍

1.宏任务

也称为任务队列,宏任务现在分为用户交互任务队列,延时任务队列,网络请求任务队列等,不仅仅局限于一个队列中;script(整体代码)、setTimeout、setInterval、UI交互事件、postMessage、Ajax,I/0,UI交互,postMessage,setImmediate(Node.js 环境)。

2.微任务

也称为Job队列,Promise队列;Promise.then catch finally、queueMicrotask、MutaionObserver、Object.observe、Promise.resolve、Promise.reject、process.nextTick(Node.js 环境)。

同步任务的主线程队列会比异步任务的宏任务和微任务先运行。

异步任务的执行顺序为:

分析以下代码,判断其执行顺序:

<!-- 点击事件宏任务 -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button>点击</button>

</body>
<script>
// 宏任务 - 用户交互事件
document.querySelector('button').addEventListener('click', function () {
    console.log('宏任务 - 用户交互事件');
});

setTimeout(()=>{
    console.log('宏任务-setTimeout')
},2000)

// 微任务 - Promise 的 then 方法
new Promise(function (resolve, reject) {
    console.log('微任务 - Promise');
    resolve();
    console.log('主线程任务')
}).then(function () {
    console.log('微任务 - Promise 的 then 方法');
});

console.log('主线程执行');
</script>
</html>

执行顺序:


微任务 - Promise
主线程任务
主线程执行
微任务 - Promise 的 then 方法
宏任务-setTimeout
宏任务 - 用户交互事件  (点击触发)

vue3 nextTick 示例代码

无注释版

import {nextTick} from 'vue'
setTimeout(() => { 
    console.log(2)
    new Promise(() => {
        console.log(9)
    })
    setTimeout(() => {
        console.log(3)
    })
})

nextTick(() => { 
    console.log(4)
    setTimeout(() => {
        console.log(5)
    })
})

let promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log(6)
    })
    resolve()
    console.log(7)
}).then(() => { 
    console.log(8)
})

console.log(1)

有注释版:

import {nextTick} from 'vue'
setTimeout(() => { 
    // 5. 此时微任务队列被清空,开始宏任务,执行宏任务,第一层
    console.log(2)
    // 6. 宏任务中的同步代码,执行
    new Promise(() => {
        console.log(9)
    })
    // 9. 宏任务的宏任务,第二层
    setTimeout(() => {
        console.log(3)
    })
})

// nextTick实际上也是执行一个微任务
nextTick(() => { 
    // 3. 开始执行微任务
    console.log(4)
    // 8. 微任务中的宏任务,先进去延时队列,第二层
    setTimeout(() => {
        console.log(5)
    })
})

// 特殊说明: new Promise()属于同步任务
let promise = new Promise((resolve, reject) => {
    // 7. 按照调用顺序,执行以下宏任务,第一层
    setTimeout(() => {
        console.log(6)
    })
    // 2. 调用resolve(),将.then()回调添加至微任务队列,会在当前执行栈的最后才执行
    resolve()
    // 1. 同步任务,所以先输出
    console.log(7)
}).then(() => { 
    // 4. 执行Promise.then()
    console.log(8)
})

console.log(1)
// 7 1 4 8 2 9 6 5 3