(JavaScript)对 async/await 的理解

当涉及到 JavaScript 中的异步编程时,async/await 是一个强大而直观的工具,它使得处理异步代码更加容易理解和编写。让我们一步步地深入了解它。

1. 异步编程背景

在 JavaScript 中,某些操作可能需要一些时间来完成,比如网络请求、文件读取、定时器等。为了不阻塞程序的执行,JavaScript 使用了异步编程模型,即不等待某些操作完成,而是继续执行下面的代码。

2. Promise

在ES6中引入了 Promise 对象,用于更好地处理异步操作。但是,使用 Promise 仍然需要嵌套回调函数,导致代码可读性不佳,这就是所谓的"回调地狱"问题。

有关Promise的内容,可以看我对于promise的理解以及promise解决了什么问题这两个文章

3. async/await 的引入

为了解决回调地狱问题,ES2017(ES8)引入了 async/await。这是一种在写异步代码时更具可读性和可维护性的语法糖

什么是语法糖

"语法糖"是计算机科学中的一个概念,指的是一种在语言中添加的、对语言的语法结构进行改进,使得特定的代码模式更容易编写或更易于阅读的语法形式。语法糖并不引入新的功能,而是提供了一种更便捷、更易读的语法。

这个术语的意义在于,尽管它使得代码编写更加方便,但它本质上并没有改变语言的功能或能力。它只是一种语法层面上的改进,简化了代码的书写方式,使得开发者更容易理解和使用某些特性。

一个常见的例子是前文提到的 async/await,它被认为是 JavaScript 中的一种语法糖。使用 async/await 让异步代码看起来更像同步代码,但它本质上仍然是基于 Promise 的异步编程。

另一个例子是 Python 中的列表推导式。列表推导式提供了一种简洁的语法来创建列表,但实际上它是对常规循环的一种语法糖。

总的来说,语法糖是一种为了提高代码可读性和编写效率而引入的语法结构。

4. async 函数

async 关键字用于定义一个返回 Promise 的异步函数。使用 async 声明的函数内部,可以使用 await 关键字来暂停函数执行,等待 Promise 解决,语法上强制规定 await 只能出现在 asnyc 函数中

javascript 复制代码
async function fetchData() {
  // 异步操作,比如请求数据
  let result = await fetchDataFromServer();
  console.log(result);
}

5. await 表达式

await 只能async 函数内部使用,用于等待一个表达式解决为 Promise。当 await 后面的表达式被解决时,它返回解决的值。

javascript 复制代码
async function fetchData() {
  let result = await fetchDataFromServer();
  console.log(result);
}

// fetchDataFromServer 返回一个 Promise
function fetchDataFromServer() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("Data fetched successfully!");
    }, 2000);
  });
}

// 使用
fetchData();

6. 错误处理

使用 try/catch 来处理异步函数中的错误,这比传统的回调错误处理更为直观

javascript 复制代码
async function fetchData() {
  try {
    let result = await fetchDataFromServer();
    console.log(result);
  } catch (error) {
    console.error("Error fetching data:", error);
  }
}

7. 同步化的写法

async/await 使得异步代码的写法更类似于同步代码,提高了代码的可读性和可维护性。

javascript 复制代码
async function fetchDataSequentially() {
  let result1 = await fetchDataFromServer1();
  console.log(result1);

  let result2 = await fetchDataFromServer2();
  console.log(result2);

  // ...
}

8.一些有关概念

  1. 返回 Promise 对象: async函数总是返回一个Promise对象。这是因为async函数内部使用Promise.resolve()来封装函数返回的值。无论async函数返回的是一个直接量还是一个经过Promise.resolve()包装的值,最终都会被封装成一个Promise对象。

    javascript 复制代码
    async function exampleAsyncFunction() {
      return 42;
    }
    
    const resultPromise = exampleAsyncFunction();
    console.log(resultPromise); // Promise { 42 }
  2. 无返回值情况: 如果async函数没有显式的return语句,或者return的是一个没有使用await关键字的表达式,那么该async函数会隐式返回Promise.resolve(undefined)

    javascript 复制代码
    async function exampleAsyncFunction() {
      // 没有 return 或者 return 后没有使用 await
    }
    
    const resultPromise = exampleAsyncFunction();
    console.log(resultPromise); // Promise { undefined }
  3. 无等待立即执行: 在没有await的情况下执行async函数时,它会立即执行并返回一个Promise对象。这是因为async函数内部的代码会立即执行,不会等待异步操作完成。

    javascript 复制代码
    async function exampleAsyncFunction() {
      console.log("Async function is executing");
      return 42;
    }
    
    const resultPromise = exampleAsyncFunction();
    console.log(resultPromise); // Promise { 42 }
  4. Promise.resolve(x)的简写: Promise.resolve(x)是一个用于快速将值x封装成Promise对象的方法。它是Promise构造函数的一个静态方法。你可以把它看作是new Promise(resolve => resolve(x))的简写形式,用于将字面量对象或其他对象封装成Promise实例。

    javascript 复制代码
    const value = 42;
    const promise = Promise.resolve(value);
    console.log(promise); // Promise { 42 }

总结

async/await 是 JavaScript 异步编程的一个巨大进步,使得异步代码更易于编写和理解。通过使异步代码看起来像同步代码,它提高了可读性,同时保留了异步编程的非阻塞特性。

相关推荐
LCG元1 小时前
【面试问题】JIT 是什么?和 JVM 什么关系?
面试·职场和发展
迷雾漫步者1 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-2 小时前
验证码机制
前端·后端
燃先生._.3 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖4 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235244 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240254 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar4 小时前
纯前端实现更新检测
开发语言·前端·javascript
寻找沙漠的人5 小时前
前端知识补充—CSS
前端·css