简明JS微任务宏任务

260 阅读3分钟

「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战

前言

单线程和异步请看:juejin.cn/post/699988…

微任务宏任务是前端的基础功底,有必要了解一下

js任务分两种微任务宏任务

  • 宏任务(macrotasks) 宏任务一般包括:整体代码script,setTimeout,setInterval、setImmediate。

  • 和微任务(microtasks) 微任务一般包括:原生Promise(有些实现的promise将then方法放到了宏任务中)、process.nextTick、Object.observe(已废弃)、 MutationObserver

下面先上代码

console.log(1)
setTimeout(()=>{
    console.log(2)
},0)
console.log(3)
Promise.resolve().then(()=>{
    console.log(4);
    setTimeout(()=>{
        console.log(5);
    })
})
console.log(6)

//结果: 1 3 6 4 2 5

看结果是不是有点意外,通常除了同步 代码外,setTimeout 和 promise 都是异步代码,按照轮训队列,按说是先进先出的。2应该在4前面。 但是promist的then确先执行啦, 这是为什么呢,其实就是前面说的,promist是微任务,setTimeout是宏任务,规则是 同一层级的代码中,执行顺序为,先同步 -> 微任务 -> 宏任务

我们再看一个例子:

setTimeout(()=>{
  console.log(0)
},0)


  new Promise(resolve => {
    console.log("1");
    for(let i = 0;i<999999999; i++){
      i === 999999999 && resolve();
    }
    console.log("2");
  
  }).then(() => {
    console.log("3");
  });
  
  
  //结果为 1 2     0

这里 根据你的电脑配置,1 2 之后会等一段时间才会执行0,不管你时间再长 setTimeout,都得等着。

然后我们再看这个

setTimeout(()=>{
  console.log(0)
},0)


setTimeout(()=>{
  new Promise(resolve => {
    console.log("1");
    for(let i = 0;i<999999999; i++){
      i === 999999999 && resolve();
    }
    console.log("2");
  
  }).then(() => {
    console.log("3");
  });
},0)

//结果为0 1 2

然后我们尝试修改第一个定时器的时间为100

setTimeout(()=>{
  console.log(0)
},100 )


setTimeout(()=>{
  new Promise(resolve => {
    console.log("1");
    for(let i = 0;i<999999999; i++){
      i === 999999999 && resolve();
    }
    console.log("2");
  
  }).then(() => {
    console.log("3");
  });
},0)

//结果为 1 2     0

得出:如果有两个相同时间的定时器则上面的先执行下面的后执行

总结:

有关定时器

  1. 定时器模块,到达时间点将其放入宏任务队列
  2. 如果主线程没有任务则执行,如果有则等待执行完成后再继续执行
  3. 如果有两个相同时间的定时器则上面的先执行下面的后执行
  4. 如果两个时间不同的定时器则时间短的先执行时间长的后执行

有关Promise

  • promise的构造函数为同步任务
  • 执行顺序永远为:同步=>微任务=>宏任务
  • 在嵌套代码中可能出现宏任务中有同步、宏任务、微任务,这时将他们放到下一次执行中的队列/主线程等待执行

setTimeout(() => {
    console.log("定时器");
    setTimeout(() => {
      console.log("timeout timeout");
    }, 0);
    new Promise(resolve => {
      console.log("settimeout Promise");
      resolve();
    }).then(() => {
      console.log("settimeout then");
    });
  }, 0);
  new Promise(resolve => {
    console.log("Promise");
    resolve();
  }).then(() => {
    console.log("then");
  });
  console.log("ssss");

执行顺序:Promise=>ssss=>then=>定时器=>settimeout Promise=>settimeout then=>timeout timeout

宏任务与微任务

  • javaScript是单线程语言
  • 所以在同一时间只能执行一个任务,称为主线程,用来执行同步任务
  • 同时还有两个任务列表用于存放异步任务,宏任务、微任务
  • 执行顺序为:主线程=>微任务=>宏任务

参考文章