瞅瞅async/await

123 阅读1分钟

异步编程主要实现

回调函数、setTimeout, Promise, Generator/yield, async/await等

async/await

promise的语法糖

await后对象状态变为resolve

async关键字用来声明异步函数,返回一个Promise对象, 若无明显返回值则返回Promise.resolve(undefined)

async function fn() {
  return 1; // Promise.resolve(1)
}
fn().then(console.log) // 1

await和yield类似,会让出JS执行线程,对后面对象进行“解包”

await期待一个实现thenable接口的对象,通常为Promise对象。如果为常规值,则当作Promise.resolve(常规值)

async function fn() {
  const res1 = await 1;
  const res2 = await { then: (callback) => callback('thenable') }
  console.log(res1); // 1
  console.log(res2); // thenable
}

reject情况

我们知道单独的Promise.reject不会被异步函数捕获,抛出未捕获错误

try {
  new Promise((resolve, reject) => {
    reject('err')
  })
} catch (error) {
  console.log(error); // (node:58599) UnhandledPromiseRejectionWarning: err
}

但是!await会返回

(async function() {
  try {
    await Promise.reject('err')
  } catch (error) {
    console.log(error); // err
  }
})()

实现sleep()

之前找实习面试经常会要求写一些异步函数

比如:输入一个数n,函数实现输出1~n,要求每隔1s输出一个。

我之前的丑陋写法👇

const fn = function(count) {
  let i = 1;
  const print = () => {
    if (i > count) return;
    setTimeout(() => {
      console.log(i++);
      print();
    }, 1000);
  }
  print()
}

async/await写法

const fn = async function(count) {
  for (let i = 1; i <= count; i++) {
    await new Promise(resolve => setTimeout(() => {
      console.log(i);
      resolve();
    }, 1000));
  }
}

在事件循环中的表现

await后跟promise对象时,会先向消息队列中添加一个改变Promise状态的任务,等到取出处理程序后再向队列中添加一个恢复执行的任务。