宏任务((macro)task)和微任务(microtask)

  • 宏任务

(macro)task,可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。
JS分为同步任务和异步任务,同步任务都在主线程上执行,形成一个执行栈

  • 微任务

microtask,可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前。
在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:

运行机制

在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:

  • 执行一个宏任务(栈中没有就从事件队列中获取)
  • 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
  • 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
  • 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
  • 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)
    自我理解如下:
  • 执行调用栈中的全局Script同步代码,这些同步代码有一些是同步语句,有一些是异步语句(比如setTimeout等);
  • 全局Script代码执行完毕后,调用栈Stack会清空;
  • 执行微队列microtask queue中所有任务,执行微任务A的过程中若又遇到微任务B,那么先按顺序执行同步事件,再执行微任务B中的异步事件,最后执行微任务A的异步事件
  • 执行宏队列macrotask queue中的任务
宏任务包含:
script(整体代码)
setTimeout
setInterval
I/O
UI交互事件
postMessage
MessageChannel
setImmediate(Node.js 环境)
微任务包含:
Promise.then
Object.observe
MutaionObserver
process.nextTick(Node.js 环境)

举例

 let  foo = () => {
        console.log(111)

        setTimeout(()=>{
            console.log(333)

            new Promise((resolve1, reject1) =>{
                 
                new Promise((resolve2,reject2) => {
                    console.log(444)
                    resolve2();
                }).then(()=>{
                    console.log(666)
                })
              console.log(555)
               resolve1(777);
            }).then(resolve => console.log(resolve))
            }, 0)

        new Promise((resolve, reject) =>
            resolve(222)
        ).then(resolve => console.log(resolve))
    }
foo();

ES6和ES7的不同写法

//ES7里
async function async1() {
  await async2()
  console.log('async1 end')
}
async function async2() {
  console.log('async2 end')
}
async1()

//ES6里
new Promise((resolve, reject) => {
  // console.log('async2 end')
  async2() 
  ...
}).then(() => {
 // 执行async1()函数await之后的语句
  console.log('async1 end')
})
new Promise((resolve, reject) => {
   setTimeout(() => resolve(new Promise(res => res(333))), 2000)
}).then(res => {
    console.log(res)
    return 222
}).then().then(res => {
    console.log(res);
    return new Promise(res => {
        setTimeout(() => { res(666) }, 1000)
    }).then(res => {
        console.log(res);
        return 999
    })
}).then(res => {
    console.log(res);
})
//结果
333
222
666
999

如果在promise里面再写一个promsie的话,由于里面的promise的then要比外面的promise的then先执行,也就是说它的nextTick更先注册,如下代码

new Promise((resolve, reject) => {
   setTimeout(() => resolve(new Promise(res => res(111))), 2000)
}).then(res => {
    console.log(res);
    new Promise((resolve,reject) => {
         resolve( 222)
    }).then(res => {
        console.log(res);
    })
return 333
}).then(res => {
    console.log(res);
})

代码若更换成如下,在内嵌的promise里加上setTimeout,输出结果就会改变

new Promise((resolve, reject) => {
   setTimeout(() => resolve(new Promise(res => res(111))), 2000)
}).then(res => {
    console.log(res);
    new Promise(res => {
        setTimeout(() => { res(333) }, 1000)
    }).then(res => {
        console.log(res);
    })
return 222
}).then(res => {
    console.log(res);
})
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容