async与await

作用

使用async/await可以编写形式同步的代码来处理异步流程;

概念
await
  • 注意点:await操作符只能在async函数中使用,否则会抛出异常;

    ‘await’ is only allowed within async functions

  • 语法

     [返回值] = await 表达式
    

    表达式可以是一个 Promise对象 或者 任意要等待的值;

    [1]表达式为Promise对象 —> 返回值为Promise的处理结果(也就是传入then方法中的数据);

    function resolveAfter2Seconds(x) {
      return new Promise(resolve => {
         setTimeout(() => {
            resolve(x);
         }, 2000);
       });
    }
    async function listChenge(){
      const res = await this.resolveAfter2Seconds(1)
      console.log('结果', res) // 1
    }
    

    [2]表达式为非Promise对象 —> 返回值为值本身

    async listChenge(){
      const res = await 1
      console.log('结果', res) // 1
    }
    
  • await表达式会立即暂停当前 async 函数的执行,让引擎继续执行后面的同步代码,等到所有同步代码执行完毕后将 await 后面的代码包装成微任务,在微任务队列中等待执行

    • promise-fulfilled—>继续执行async function;
    • promise-rejected—>将Prmoise的异常原因抛出;
async函数
  • 定义:使用async关键字声明的函数被称为async函数;

  • 语法:

     async function 函数名(){}
    
  • 返回值:
    [1] 若是没有返回值,默认值为undefined

    [2] 若是存在返回值

    • 若是返回值为promise对象,直接返回

    • 若是返回值不是一个promise,async函数将会将值包装为一个Promise

        async function test(){
          return 222
        }
        
        // 等价于
        async function test(){
          return new Promise(){ resolve(222)}
        }
      
async与await结合使用
  • async中存在0个或者多个await;
  • await表达式会立即暂停当前 async 函数的执行,让引擎继续执行后面的同步代码,等到所有同步代码执行完毕后将 await 后面的代码包装成微任(Promise),在微任务队列中等待执行,只有当其等待的基于 promise 的异步操作被兑现或被拒绝之后才会恢复进程。promise 的解决值会被当作该 await 表达式的返回值

现在通过下面代码真正理解一下awiat代码的执行流程

console.log('Script start');

setTimeout(() => {
  console.log('setTimeout');
}, 0);

async function asyncFunc() {
  console.log('2');
  await Promise.resolve(); // 等待一个立即解决的Promise
  console.log('4');
}

asyncFunc();

Promise.resolve().then(() => {
  console.log('3');
});

console.log('Script end');

// 输出顺序:
// Script start
// 2. Inside asyncFunc - before await
// Script end
// 3. Promise.then (Microtask)     <- 微任务1
// 4. Inside asyncFunc - after await (Microtask) <- 微任务2
// setTimeout (Macrotask)          <- 宏任务

上述代码3和4哪个先打印出来呢?

  • ‘Script start’
  • 将setTimeout加入宏任务
  • ‘2’ 暂停async函数的执行 等待所有同步代码执行完毕( 此时没有将这里的微任务加入微任务队列)
  • 将Promise微任务加入微任务队列
  • ‘Script end’
  • 此时同步任务执行完毕 将await后面的代码包装成微任务加入队列
  • 执行微任务 遵循先入先出 所以 先打印3再打印4
  • 执行宏任务 ‘setTimeout’
  • 总结: 执行顺序为 ‘Script start’ ‘2’ ‘Script end’ ‘3’ ‘4’ ‘setTimeout’

思考题

async function awaitMethod(){
  const res = await new Promise((resolve,reject)=>{
    setTimeout(()=>{
      console.log('111')
      resolve()
    },5000)
  })
  console.log('333')
}
function listChenge(){
  this.awaitMethod()
  console.log('222')
}
  • 答案:先打印222,等待5秒打印111,333

  • 执行步骤:

    [1] 调用awaitMethod方法,里面存在await中断awaitMethod方法的执行
    [2] 打印222
    [3] 5秒钟之后打印111,Promise结束,打印333

const res = await new Promise((resolve,reject)=>{
    setTimeout(()=>{
      console.log('111')
      resolve()
    },5000)
  })
  console.log('333')
}
async function listChenge(){
  await this.awaitMethod()
  console.log('222')
}
listChenge()

答案: 等待5s之后打印111,333,222

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐