宏任务与微任务

92 阅读2分钟

同步任务和异步任务

JavaScript是单线程执行的语言,在同一个时间只能做一件事情。这就导致后面的任务需要等到前面的任务完成才能执行,如果前面的任务很耗时就会造成后面的任务一直等待。为了解决这个问题JS中出现了同步任务和异步任务。
同步任务:在主线程上排队执行的任务只有前一个任务执行完毕,才能执行后一个任务,形成一个执行栈。
异步任务:不进入主线程,而是进入任务队列,当主线程中的任务执行完毕,就从任务队列中取出任务放进主线程中来进行执行。由于主线程不断重复的获得任务、执行任务、再获取再执行,所以这种机制被叫做事件循环(Event Loop)
JavaScript把异步任务又做了进一步的划分,创建异步任务主要分为宏任务与微任务两种。ES6 规范中,宏任务(Macrotask) 称为 Task, 微任务(Microtask) 称为 Jobs。宏任务是由宿主(浏览器、Node)发起的,而微任务由 JS 自身发起。
宏任务(macrotask):异步Ajax请求, setTimeout、setInterval, 文件操作
微任务(microtask):Promise.then、Promise.catch和Promise.finally、process.nextTick轮询过程

宏任务与微任务.png

setTimeout(function() {
    console.log('1');
});   
new Promise(function(resolve) {
    console.log('2');
    resolve()
}).then(function() {
  console.log('3');
});
console.log('4');

未命名文件 (2).png

案例

console.log('1');
setTimeout(function() {
    console.log('2');
    new Promise(function(resolve) {
      console.log('3');
      resolve()
    }).then(function() {
      console.log('4');
    })
});
new Promise(function(resolve) {
  console.log('5');
  resolve()
}).then(function() {
  console.log('6');
});

setTimeout(function() {
  console.log('7');
  new Promise(function(resolve) {
    console.log('8');
    resolve()
  }).then(function() {
    console.log('9');
  });
})

// 1 5 6 2 3 4 7 8 9
setTimeout(() => {
    console.log('timer_1');
    setTimeout(() => {
      console.log('timer_3')
    }, 0);
    new Promise(resolve => {
        resolve()
        console.log('new promise')
    }).then(() => {
        console.log('promise then')
    });
    new Promise(resolve => {
        resolve()
        console.log('new promise2')
    }).then(() => {
        console.log('promise then2')
    })
}, 0)
   
setTimeout(() => {
    console.log('timer_2')
}, 0)
console.log('========== Sync queue ==========');

//========== Sync queue ==========
// timer_1  new promise  new promise2  promise then  promise then2   timer_2  timer_3

async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
};
async function async2() {
    console.log('async2');
};
   
console.log('script start');
   
setTimeout(function() {
    console.log('setTimeout');
}, 0);

async1();

new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function() {
    console.log('promise2');
});
console.log('script end');

// script start   async1  start   async2      promise1    
// script end     async1  end     promise2    setTimeout