返回

突破框架,发现JS异步流控制新世界

前端

异步新世界

最近使用Egg写了一个Node项目,它的异步流控制功能真是让人惊艳,不禁泪流满面。废话不多说,先来看一段代码,体验一下这种奇妙的感觉:

const findPerson = async () => {
  // 异步查找人员信息
  return await Person.findOne({ name: 'John Doe' });
};

const findOrder = async (person) => {
  // 异步查找订单信息
  return await Order.findOne({ personId: person._id });
};

const payOrder = async (order) => {
  // 异步支付订单
  return await Payment.pay(order.id);
};

const purchase = async () => {
  // 串行执行异步任务
  const person = await findPerson();
  const order = await findOrder(person);
  const result = await payOrder(order);

  // 返回支付结果
  return result;
};

以上代码是付款的简易流程,先找人,再找订单,最后支付。其中找人、找订单和支付都是异步逻辑。写出这段代码的时候,回忆把我带到了Callback的时代。Callback是我们最熟悉的异步控制方式,但它存在着明显的缺点:

  • 代码混乱、嵌套严重,可读性差
  • 调试困难,错误处理复杂
  • 难以维护,扩展性差

为了解决这些问题,JS引入了多种异步控制方式,包括:

  • 协程(Coroutine)
  • 生成器(Generator)
  • Promise
  • Async/Await

协程与生成器

协程是一种轻量级的线程,它可以暂停自己的执行,并在稍后继续执行。生成器是协程的实现方式之一,它允许我们在函数中使用yield暂停函数的执行,并在稍后使用next()方法继续执行。

使用协程和生成器进行异步控制,可以大大提高代码的可读性和可维护性。例如,我们可以使用生成器重写上面的代码:

async function* purchase() {
  // 异步查找人员信息
  const person = yield findPerson();

  // 异步查找订单信息
  const order = yield findOrder(person);

  // 异步支付订单
  const result = yield payOrder(order);

  // 返回支付结果
  return result;
}

// 使用生成器函数进行异步控制
const purchaseFlow = purchase();
purchaseFlow.next().value.then((result) => {
  const order = result.value;
  purchaseFlow.next(order).value.then((result) => {
    const paymentResult = result.value;
    purchaseFlow.next(paymentResult);
  });
});

Promise

Promise是一种表示异步操作的最终完成或失败的返回值。Promise对象有两个状态:resolvedrejectedresolved表示异步操作成功完成,rejected表示异步操作失败。

使用Promise进行异步控制,可以大大提高代码的可读性和可维护性。例如,我们可以使用Promise重写上面的代码:

const purchase = async () => {
  // 异步查找人员信息
  const person = await findPerson();

  // 异步查找订单信息
  const order = await findOrder(person);

  // 异步支付订单
  const result = await payOrder(order);

  // 返回支付结果
  return result;
};

Async/Await

Async/Await是ES8中引入的异步控制语法糖,它允许我们使用asyncawait关键字来编写异步代码,就像编写同步代码一样。

使用Async/Await进行异步控制,可以大大提高代码的可读性和可维护性。例如,我们可以使用Async/Await重写上面的代码:

const purchase = async () => {
  // 异步查找人员信息
  const person = await findPerson();

  // 异步查找订单信息
  const order = await findOrder(person);

  // 异步支付订单
  const result = await payOrder(order);

  // 返回支付结果
  return result;
};

结语

JS提供了多种异步控制方式,包括协程、生成器、Promise和Async/Await。这些异步控制方式各有优缺点,我们可以根据具体情况选择合适的异步控制方式。