(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 异步编程的一个巨大进步,使得异步代码更易于编写和理解。通过使异步代码看起来像同步代码,它提高了可读性,同时保留了异步编程的非阻塞特性。

相关推荐
罗_三金6 分钟前
前端框架对比和选择?
javascript·前端框架·vue·react·angular
Redstone Monstrosity13 分钟前
字节二面
前端·面试
东方翱翔20 分钟前
CSS的三种基本选择器
前端·css
Fan_web42 分钟前
JavaScript高级——闭包应用-自定义js模块
开发语言·前端·javascript·css·html
yanglamei19621 小时前
基于GIKT深度知识追踪模型的习题推荐系统源代码+数据库+使用说明,后端采用flask,前端采用vue
前端·数据库·flask
千穹凌帝1 小时前
SpinalHDL之结构(二)
开发语言·前端·fpga开发
dot.Net安全矩阵1 小时前
.NET内网实战:通过命令行解密Web.config
前端·学习·安全·web安全·矩阵·.net
叫我:松哥1 小时前
基于Python flask的医院管理学院,医生能够增加/删除/修改/删除病人的数据信息,有可视化分析
javascript·后端·python·mysql·信息可视化·flask·bootstrap
Hellc0071 小时前
MacOS升级ruby版本
前端·macos·ruby
UestcXiye1 小时前
面试算法题精讲:求数组两组数差值和的最大值
面试·数据结构与算法·前后缀分解