async/await以及js中的微任务和宏任务

  • Post author:
  • Post category:其他


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')

关于上述这道题除了要考虑同步异步的问题,还涉及到js中的微任务和宏任务,就这道题我说一下关于我的理解。

同步和异步任务分别进入不同的执行”场所”,同步的任务进入主线程,异步的进入Event Table并注册函数。当异步函数完成时,Event Table会将这个函数移入Event Queue。主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。上述过程会不断重复,也就是常说的Event Loop(事件循环)。

除此之外,在js中还存在宏任务和微任务。

js中的宏任务一般是:包括整体代码script,setTimeout,setInterval。

微任务是:Promise,process.nextTick。

说一下我对于async/await的理解:

1.async做了一件什么事情?

async将你的函数返回值转换为promise对象,不需要显式地返回promise对象,async关键字自动将函数的返回值变为promise对象。

2.await的作用

await关键字只能在带有async关键字的函数内部使用,在外部使用时会报错。await等待的是右侧的[表达式结果],如果右侧是一个函数,等待的是右侧函数的返回值,如果右侧的表达式不是函数则直接是右侧的表达式。await在等待时会让出线程阻塞后面的执行。await的执行顺序为从右到左,会阻塞后面的代码执行,但并不是直接阻塞await的表达式。

await之后如果不是promise,await会阻塞后面的代码,会先执行async外面的同步代码,等外面的同步代码执行完成在执行async中的代码。

如果它等到的是一个 promise 对象,await 也会暂停async后面的代码,先执行async外面的同步代码,等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果。

一段代码执行时,会先执行宏任务中的同步代码:

  • 如果执行中遇到

    setTimeout

    之类宏任务,那么就把这个

    setTimeout

    内部的函数推入「宏任务的队列」中,下一轮宏任务执行时调用。

  • 如果执行中遇到

    promise.then()

    之类的微任务,就会推入到「当前宏任务的微任务队列」中,在本轮宏任务的同步代码执行都完成后,依次执行所有的微任务1、2、3。

上述这道题的执行顺序为:

第一个宏任务:

console.log('script start')

第一个宏任务中的第一个微任务:

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

async function async2() {
   console.log('async2')
}

在第一个微任务中存在await关键字,因此先输出

async1 start

接着输出

async2

await阻塞后面的代码执行,因此跳出async函数执行下一个微任务

第一个宏任务中的第二个微任务:

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

先输出:

promise1

碰到promise.then这个微任务会先执行本轮宏任务的同步代码再执行微任务

接着输出:

script end

再挨个执行所有的微任务,依次输出:

promise2
async1 end

第一个宏任务执行完成,执行第二个宏任务:

setTimeout(function() {
   console.log('setTimeout')
}, 0)

输出结果为:

setTimeout

这就是这道题的解题思路。



版权声明:本文为qq_41681425原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。