关于 async 和 await 的最新理解

2,241 阅读3分钟

1、基于 Promise 的 async 和 await

  • 什么是 async 和 await 呢?

async(异步的) 与 await(等待) 一般作为一对“连体婴”存在,生来就是为 Promise 所服务的,可以说 async 和 await 就是 Promise 的进化版,是 Promise 的语法糖。

  • 首先来说一说 async 的用法
async function async1(){ ... }  //正确
const async async2 = function(){ ... }  //错误
  • await 必须在 async 函数的内部使用,且必须为“直系”
  • 示例:
async function async1(){
    function f1(){
        await console.log(1)
    }
}
  • 报错:Uncaught SyntaxError: await is only valid in async function

2、async 的本质

  • async 的本质就是会隐式的返回一个 Promise 对象
(async function async1(){
    return 'hello world'
})()

Promise {<resolved>: "hello world"}  //返回值
  • 可以看到,一个声明为 async 的函数,默认的返回值就是一个 Promise 对象,等同于
(async function async1(){
    return Promise.resolve('hello world')
})()

3、await 的本质

  • await 顾名思义就是等待一会,只要 await 声明的函数还没有返回,那么下面的程序是不会去执行的。这就是字面意义的等待一会(等待返回再去执行)。
  • 一旦遇到await 就立刻让出线程,阻塞后面的代码,等候之后,对于await来说分两种情况
    • 不是 Promise 对象。如果不是 Promise,await 会阻塞后面的代码,先执行 async 外面的同步代码,同步代码执行完毕后,在回到 async 内部,把 Promise 的东西,作为 await 表达式的结果
    • 是 Promise 对象。如果它等到的是一个 Promise 对象,await 也会暂停 async 后面的代码,先执行 async 外面的同步代码,等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果。

4、相关示例题目

题目1:

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

//async1 start
//async2
//script start
//async1 end
  • 要注意的是,,async2() 是作为同步函数来执行的,因此会在输出 aycnc1 start 后立刻输出 async2

题目2:

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

await 语句是同步的,await语句后面全部代码才是异步的微任务,

题目3:

async function t1 () {
  console.log(1)
  console.log(2)
  await Promise.resolve().then(() => console.log('t1p'))
  console.log(3)
  console.log(4)
}

async function t2() {
  console.log(5)
  console.log(6)
  await Promise.resolve().then(() => console.log('t2p'))
  console.log(7)
  console.log(8)
}

t1()
t2()

console.log('end')
  • 打印结果:
1
2
5
6
end
t1p
t2p
3
4
7
8

题目4:

async function t1 () {
	console.log(1)
	console.log(2)
	new Promise( function ( resolve ) {
		console.log( 'promise3' )
		resolve();
	} ).then( function () {
		console.log( 'promise4' )
	} )
	await new Promise( function ( resolve ) {
		console.log( 'b' )
		resolve();
	} ).then( function () {
		console.log( 't1p' )
	} )

	console.log(3)
	console.log(4)
	new Promise( function ( resolve ) {
		console.log( 'promise5' )
		resolve();
	} ).then( function () {
		console.log( 'promise6' )
	} )
}

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

async function t2() {
	console.log(5)
	console.log(6)
	await Promise.resolve().then(() => console.log('t2p'))
	console.log(7)
	console.log(8)
}

t1()

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

t2()

console.log('end');
  • 打印结果:
1
2
promise3
b
promise1
5
6
end
promise4
t1p
promise2
t2p
3
4
promise5
7
8
promise6
setTimeout
  • 注意,await 下一行开始的代码必须等 await 语句执行完成后(包括微任务完成),才能执行。也就是说,只有运行后面语句,才把await语句后面的全部代码加入到微任务行列,所以,在遇到 await Promise 时,必须等 await Promise 函数执行完毕才能对 await 语句后面的全部代码加入到微任务中,所以,在等待await Promise.then微任务时,
  1. 运行其他同步代码。

  2. 等到同步代码运行完,开始运行 await promise.then 微任务。

  3. await promise.then微任务完成后,把await语句后面的全部代码加入到微任务行列。