Skip to content

JavaScript 中的 async await 是什么?

简介

异步函数使用 asyncawait 语法来等待一个 promise 被解析。为了更好地理解这篇文章,建议了解 promise 的工作原理。你可以在这里了解它们

回调地狱

引入 async/await 的原因之一是为了避免众所周知的 "回调地狱",即函数嵌套多层。当一个函数的结果需要进一步查询和验证时,这种情况非常常见。

我们将创建一个简单的流程来举例说明 "回调地狱":

javascript
function suma(a, b, cb) {
  cb(a + b); // 在回调中返回两个数的和
}
function restar(valor, cantidad, cb) {
  cb(valor - cantidad); // 从一个值中减去一定数量
}
function esMayorACero(valor, cb) {
  if (valor > 0) {
    cb('Mayor a cero');
  } else {
    cb('Menor a cero');
  }
}

const x = 10;
const y = 20;
// 如果有更多的派生流程,它会嵌套得越来越深
suma(x, y, function (resultado_de_suma) {
  // 结果:30 
  restar(resultado_de_suma, 15, function (resultado_de_resta) {
    // 结果:15
    esMayorACero(resultado_de_resta, function (respuesta) {
      // 结果:'Mayor a cero'
      console.log(respuesta); // Mayor a cero
    });
  });
});

这是一个有代表性的例子,因为回调最常用于服务器请求等异步过程。

Promise

为了重写前面的例子,我们将把函数转换为 promise:

javascript
function suma(a, b) {
  return new Promise(function (resolve, reject) {
    resolve(a + b);
  });
}
function restar(valor, cantidad) {
  return new Promise(function (resolve, reject) {
    resolve(valor - cantidad);
  });
}
function esMayorACero(valor) {
  return new Promise(function (resolve, reject) {
    if (valor > 0) {
      resolve('Mayor a cero');
    } else {
      resolve('Menor a cero');
    }
  });
}

const x = 10;
const y = 20;

suma(x, y)
  .then(function (resultado_de_suma) {
    // 结果:30
    return restar(resultado_de_suma, 15);
  })
  .then(function (resultado_de_resta) {
    // 结果:15 
    return esMayorACero(resultado_de_resta);
  })
  .then(function (respuesta) {
    // 结果:'Mayor a cero'
    console.log(respuesta);
  });

通过返回一个 promise,我们可以在它们被解析时链式调用 then()

Async/Await

现在我们将使用 async/await 重写这个例子。由于它与 promise 一起工作,我们将使用上一个代码中声明的相同函数。

Async/Await 只能在异步函数中工作,即语法为 async function function_name () {} 的函数。

javascript
const x = 10;
const y = 20;

// 带有 "async" 的异步函数
async function mayorACero() {
  try {
    let resultado_de_suma = await suma(x, y); // 结果:30
    let resultado_de_resta = await restar(resultado_de_suma, 15); // 结果:15
    let respuesta = await esMayorACero(resultado_de_resta); // 结果:'Mayor a cero'
    console.log(respuesta);
  } catch (err) {
    // 错误处理
  }
}

mayorACero(); // 结果:'Mayor a cero'

如果我们在 async 函数之外使用 await 语法,就会导致错误。

得益于 async/await,我们可以以更加顺序化的方式处理异步函数,为我们的代码提供更多的清晰度。

当使用 await 时,建议将其放在 try {} catch() {} 中,以便在 catch() {} 中能够控制失败的 promise。这是因为如果一个 promise 在 try 中失败,错误将传播到 catch 块。

因为 async/await 相对较新,建议谨慎使用,因为它不能在 IE11 等旧浏览器中工作。你可以在这里查看它的支持情况。

我希望这篇文章能帮助你熟悉 ECMAScript7 中的一些新特性,在本例中是 async/await。