宏任务和微任务

208 阅读2分钟

异步宏任务: setTimeout,setInterval,requestAnimationFrame,script代码
异步微任务: promise.then,process.nextTick(node环境),MutationObserver

  1. js是单线程的,js代码只能在一个线程上运行,但是任务有同步任务和异步任务之分,浏览器为了处理异步任务,就会模拟出多个线程,这多个线程就有优先级,分异步宏任务和异步微任务,微任务优先级 > 宏任务
  2. js需要实现异步,是因为异步代码执行时间过长,等待返回,会导致执行阻塞,页面内容长时间无法显示
  3. js通过 event loop 机制实现异步
  4. 由浏览器发起的异步请求是异步宏任务,js引擎发起的异步请求是异步微任务
  5. 宏任务里面仍然可以分同步任务和异步任务(比如 script)

事件循环: 从宏任务队列中取出一个宏任务1(script), 执行宏任务1内的同步代码, 遇到宏任务2(setTimeout),将宏任务2加入宏任务队列,遇到微任务(promise.then),将微任务加入微任务队列 等主线程上的任务执行结束,去微任务队列取任务执行,微任务队列取空后,去宏任务队列取任务执行,循环往复

案例1

结果:2 5 3 4 1

setTimeout(function timeout() {
  console.log(1);
});

new Promise((resolve) => {
  console.log(2);
  resolve("a");
})
  .then(function th1() {
    console.log(3);
  })
  .then(function th2() {
    console.log(4);
  });

console.log(5);

案例2

结果: a, b, c ,before timeout, also before timeout,d

setTimeout((_) => console.log("d")); 

new Promise((resolve) => {
  resolve("p");
  console.log("a"); 
}).then((_) => {
  console.log("c"); 
  Promise.resolve()
    .then((_) => {
      console.log("before timeout"); 
    })
    .then((_) => {
      Promise.resolve().then((_) => {
        console.log("also before timeout");
      });
    });
});

console.log("b");

案例3

结果:a,b,7,c,8,before timeout,also before timeout,d,9,11,12,2,4,5,13

setTimeout((_) => console.log("d"));

new Promise((resolve) => {
  resolve("a");
  console.log("a");
}).then((_) => {
  console.log("c");
  Promise.resolve()
    .then((_) => {
      console.log("before timeout");
    })
    .then((_) => {
      Promise.resolve().then((_) => {
        console.log("also before timeout");
      });
    });
});

console.log("b");

setTimeout(function () {
  console.log("2");
  new Promise(function (resolve) {
    console.log("4");
    resolve("4");
  }).then(function () {
    console.log("5");
    setTimeout(() => {
      console.log(13);
    }, 0);
  });
}, 1000);
new Promise(function (resolve) {
  console.log("7");
  resolve("7");
}).then(function () {
  
  console.log("8");
});
setTimeout(function () {
  console.log("9");
  new Promise(function (resolve) {
    console.log("11");
    resolve("11");
  }).then(function () {
    console.log("12");
  });
});