JS是单线程,所以理论是会出现阻塞的问题,为了解决该问题,所以通过单线程来模拟多线程进行解决。

同步任务:在程序中可以立即执行的任务,比如console.log等,可以立刻看到结果。

异步任务:在程序中需要等待才能看到结果的任务,比如接口请求、定时器、延时器等。

代码从上向下执行进行执行栈,会判断任务是同步还是异步。
同步任务:则进入主线程,同步任务全部执行完毕,获取任务结果。
异步任务:则进入任务表中注册函数,当指定的函数执行完成后,注册回调函数,任务表则将这个函数移到任务队列当中。主线程内任务全部执行完成后,会去任务队列中读取对应函数,进入主线程执行,
事件监听会监听异步任务的状态,如果可以执行回调,就会将对应的任务放到任务队列里。
上述过程会不断循环,这就是任务循环

宏任务与微任务

首先:宏任务与微任务都属于异步任务
先执行微任务后执行宏任务

2.宏任务与微任务有哪些

宏任务

I/O、setTimeout、setInterval、setImmediate

微任务

process.nextTick 、Promise.then/.catch/.finally

3.宏任务与微任务的执行顺序

JavaScript是单线程的,常用的任务分为同步任务和异步任务。在每轮事件循环中,主线程会先执行完同步任务,再执行异步任务。

  整体JavaScript代码将作为一个宏任务执行,先将同步任务进入主线程执行,异步任务进入事件表(Event Table)并注册回调函数(如:success、then、catch等)。当异步事件完成,回调函数进入事件队列等待被调用。而来自不同任务源的任务会进入不同的任务队列。其中setTimeout与setInterval是同源的。

  js引擎Monitoring Process进程会不断的检查主线程执行栈是否为空,一旦为空,就会检查事件队列中是否有等待被调用的函数,如果有,主线程将依次读取回调函数并调用。否则执行下一轮事件循环。

微任务存到一个数组中,红任务存到链表中。

  在每轮事件循环中微任务队列的优先级高于宏任务队列。微任务队列中排队的所有微任务都在同一周期内处理,而这些微任务本身也可以将其他微任务添加到微任务队列中中执行,只有这些微任务全部执行完成时,才会执行下一个宏任务。

4.案例

案例1



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

1.遇到setTimout,异步宏任务,放入宏任务队列中
2.遇到new Promise,new Promise在实例化的过程中所执行的代码都是同步进行的,所以输出2
3.而Promise.then中注册的回调才是异步执行的,将其放入微任务队列中
4.遇到同步任务console.log(‘5’);输出5;主线程中同步任务执行完
5.从微任务队列中取出任务到主线程中,输出3、 4,微任务队列为空
6.从宏任务队列中取出任务到主线程中,输出1,宏任务队列为空

案例2

(先同步后异步,先微任务,再宏任务)

console.log('script start');  // 同步
 
setTimeout(function () {
  console.log('setTimeout1');  // 异步
}, 300);
 
setTimeout(function () {
  console.log('setTimeout2');  // 异步
}, 0);
 
new Promise(resolve => {
  resolve()
  console.log('promise1');  // 同步
}).then(() => {
  console.log('promise2');  // 异步
})
 
console.log('script end');  // 同步
 
// script start
// promise1
// script end
// promise2
// setTimeout2
// setTimeout1


process.nextTick()先于Promise.then()执行, setTimeout()与setImmediate()执行顺序取决于setTimeout的执行周期与设备性能。

process.nextTick 属于 idle观察者 idle观察者 > IO观察者 > check观察者

console.log(1);
setTimeout(function () {
   console.log(2);
   let promise = new Promise(function (resolve, reject) {
      console.log(3);
      resolve();
   }).then(function () {
      console.log(4);
   });
}, 1000);
setTimeout(function () {
   console.log(5);
   let promise = new Promise(function (resolve, reject) {
      console.log(6);
      resolve();
   }).then(function () {
      console.log(7);
   });
}, 0);
let promise = new Promise(function (resolve, reject) {
   console.log(8);
   resolve()
}).then(function () {
   console.log(9);
}).then(function () {
   console.log(10)
});
console.log(11);


1, 8 ,11 ,  9 , 10 , 5 , 6, 7,  2,  3, 4 
 

注意注意

不同版本的node 执行顺序不一样

function test () { 
   console.log('start') 
   setTimeout(() => { 
       console.log('children2') 
       Promise.resolve().then(() => {
           console.log('children2-1')
       }) 
   }, 0) 
   setTimeout(() => { 
       console.log('children3') 
       Promise.resolve().then(() => {
           console.log('children3-1')
       })
   }, 0) 
   Promise.resolve().then(() => {
       console.log('children1')
   }) 
   console.log('end') 
}
test()

注意: 以上代码在 node11 以下版本的执行结果(先执行所有的宏任务,再执行微任务)

start
end
children1
children2
children3
children2-1
children3-1

注意: 以上代码在 node11 及浏览器的执行结果(顺序执行宏任务和微任务)


start
end
children1
children2
children2-1
children3
children3-1