概述
我们都知道js是一个单线程,里面的的请求方式分为两种,一种是同步请求,一种是异步请求,同步方法先执行完毕,然后再去异步任务队列中查看有没有异步任务,有才会执行。
在JavaScript中,所有的任务都可以分为
同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
异步任务:异步执行的任务,比如ajax网络请求,setTimeout定时函数等
常见的宏任务
script、setTimeout、setInterval、setImmediate
常见的微任务
一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前
Promise中的then、async、await、process.nextTick(Node.js)、MutationObserver(监听DOM变化的事件)、Object.observe(已废弃;Proxy 对象替代)
关于两者之间的区别:微任务是批量执行、宏任务则是一个一个的执行。
- 执行一个宏任务,如果遇到微任务就将它放到微任务的事件队列中
 
- 当前宏任务执行完成后,会查看微任务的事件队列,然后将里面的所有微任务依次执行完
 
这里我们可以看到,script标签包含的下面的代码块,那么这就属于是第一个异步任务,也就是宏任务,首先去执行它
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   | <script>     console.log('1')      setTimeout(function () {         console.log('2')     });     new Promise(function (resolve) {          console.log('3');           resolve();     }).then(function () {          console.log('4')         setTimeout(function () {             console.log('5')          });     });     new Promise(function (resolve) {             console.log('6');              resolve();         }).then(function () {              console.log('7')         setTimeout(function () {             console.log('8')          });      }); </script>
   | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
   | setTimeout(() => {     console.log(0) }, 0)   new Promise((resolve, reject) => {     console.log(1)     resolve() }).then(() => {     console.log(2)     new Promise((resolve, reject) => {         console.log(3)         resolve()     }).then(() => {         console.log(4)     }).then(() => {         console.log(5)     }) }).then(() => {     console.log(6) })   new Promise((resolve, reject) => {     console.log(7)     resolve() }).then(() => {     console.log(8) })
  172384650
  | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
   | console.log(1); new Promise((resolve, reject) => {     console.log(2);     setTimeout(() = >{         console.log(3)     });     resolve() }).then(() =>{     console.log(4) });
  setTimeout(() =>{     console.log(5) }); console.log(6)
  1,2,6,4,3,5
 
  <script>     console.log('1')      setTimeout(function () {         console.log('2')     });     new Promise(function (resolve) {          console.log('3');           resolve();     }).then(function () {          console.log('4')         setTimeout(function () {             console.log('5')          });     });     new Promise(function (resolve) {             console.log('6');              resolve();         }).then(function () {              console.log('7')         setTimeout(function () {             console.log('8')          });      });     console.log(9) </script>
  136947258
  let promise = new Promise(resolve=>{     setTimeout(()=>{         resolve();         console.log('1')     },0);     console.log('2') }).then(value=>console.log('3')) console.log('4') 2413
 
  console.log(1) // 遇到 console.log(1) ,直接打印 1
  // 遇到定时器,属于新的宏任务,留着后面执行 setTimeout(()=>{      console.log(2) }, 0)
  // 遇到 new Promise,这个是直接执行的,打印 'new Promise' new Promise((resolve, reject)=>{     console.log('new Promise')     resolve() }).then(()=>{ // .then 属于微任务,放入微任务队列,后面再执行     console.log('then') })
  console.log(3) // 遇到 console.log(3) 直接打印 3
  // 好了本轮宏任务执行完毕,现在去微任务列表查看是否有微任务,发现 .then 的回调,执行它,打印 'then' // 当一次宏任务执行完,再去执行新的宏任务,这里就剩一个定时器的宏任务了,执行它,打印 2
 
  实际结果是:1=>'new Promise'=> 3 => 'then' => 2
   | 
 
总结
同步>微任务>宏任务
async与await
async 是异步的意思,await则可以理解为 async wait。所以可以理解async就是用来声明一个异步方法,而 await是用来等待异步方法执行
async函数返回一个promise对象,下面两种方法是等效的
1 2 3 4 5 6 7 8
   | function f() {     return Promise.resolve('TEST'); }
 
  async function asyncF() {     return 'TEST'; }
  | 
 
正常情况下,await命令后面是一个 Promise对象,返回该对象的结果。如果不是 Promise对象,就直接返回对应的值。不管await后面跟着的是什么,await都会阻塞后面的代码
1 2 3 4 5 6 7 8 9 10 11 12
   | async function fn1 (){     console.log(1)     await fn2()     console.log(2)  }
  async function fn2 (){     console.log('fn2') }
  fn1() console.log(3)
  | 
 
上面的例子中,await会阻塞下面的代码(即加入微任务队列),先执行 async外面的同步代码,同步代码执行完,再回到 async 函数中,再执行之前阻塞的代码
所以上述输出结果为:1,fn2,3,2
参考文章