写点什么

Web 前端入门:JavaScript async & await 的异步任务进化之路

  • 2025-07-18
    福建
  • 本文字数:1914 字

    阅读完需:约 6 分钟

JS 中异步任务随处可见,比如:

1、用户交互的点击、输入 2、网络请求的 fetch、ajax、WebSocket3、资源中的图片、脚本加载 4、定时任务 setTimeout、setInterval、动画 5、Web Worker 中的后台任务

以上这些地方都能见到 JS 异步任务使用场景。

不过 JS 的异步任务 使用方法 却经过了多次迭代,多次进化才像一个完全体~~


回调方法


最原始的使用方法,目前也还能在各种钩子函数中见到 回调函数 的身影。

function asyncTask(callback) {  console.log('开始执行异步任务');  setTimeout(() => {    console.log('异步任务执行完毕');    callback && callback();  }, 1000);}
// 传入匿名函数用于回调方法asyncTask(() => { console.log('异步任务执行完毕,回调函数执行完毕');});
复制代码


以上 asyncTask 传入的 匿名函数 便是回调方法(也称为回调函数),回调方法将会在等到 setTimeout 执行完毕时执行。


Promise


在使用回到函数时,容易陷入回调地狱,而 Promise 的出现便是为了解决回调地狱问题。

使用回调函数嵌套太多时,就会有像套娃一样的代码,比如:

a(() => {  b(()  => {    c(() => {      d(() => {})    })  })})
复制代码


使用 Promise 优化之后可以是这样:

a().then(() => {  return b()}).then(() => {  return c()}).then(() => {  return d()})
复制代码


最开始的 setTimeout 函数使用 Promise 优化之后:

function asyncTask() {  return new Promise((resolve) => {    console.log('开始执行异步任务');    setTimeout(() => {      console.log('异步任务执行完毕');      resolve();    }, 1000);  });}
// Promise 链式调用asyncTask().then(() => { console.log('异步任务执行完毕,回调函数执行完毕');});
复制代码


async & await


使用 Promise 的链式调用确实大大的改善了回调地狱,但还是绕不过代码不太优雅的问题,于是乎 JS 标准定制的那群大佬,就在 ES2017(ES8) 中引入了 async 和 await 关键字,由于优化 JS 中的异步逻辑,使得代码就像同步任务一样。

async & await 仅仅是 Promise 的语法糖,所以它俩基本是与 Promise 深度绑定~~

改写上面的 Promise 示例:

(async () => {  function asyncTask() {    return new Promise((resolve) => {      console.log('开始执行异步任务');      setTimeout(() => {        console.log('异步任务执行完毕');        resolve();      }, 1000);    });  }
// await 调用 await asyncTask() console.log('异步任务执行完毕,回调函数执行完毕');})()
复制代码


await 关键字用于等待一个 Promise 任务完成,然后继续执行后续的代码。

注意:在使用 await 关键字时,必须在外层作用域的函数身上加上 async 关键字,否则会报错。


顶层 await


在 ES2023 发布后,异步任务又被革命了,在 ES 模块 中,允许在顶层作用域使用 await 关键字而不必再套在 async 函数中。


<script type="module">  function asyncTask() {    return new Promise((resolve) => {      console.log('开始执行异步任务');      setTimeout(() => {        console.log('异步任务执行完毕');        resolve();      }, 1000);    });  }
// await 调用 await asyncTask() console.log('异步任务执行完毕,回调函数执行完毕');</script>
复制代码


注意上面的 type="module",表示使用 ES 模块语法,这种语法 Chrome 61 版本开始支持(2017 年后)。

如果没有 type="module",表示使用正常的 script 执行脚本,上面的代码会报错:

Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules
复制代码

表示 await 必须在 async 函数中使用,在顶层使用时候必须放在 ES 模块中。


返回内容


await 关键字可以等待一个 Promise resolve 方法返回值:

(async () => {  function asyncTask() {    return new Promise((resolve) => {      console.log('开始执行异步任务');      setTimeout(() => {        console.log('异步任务执行完毕');        resolve({ name: '前端路引' });      }, 1000);    });  }
// await 调用 const res = await asyncTask() console.log('异步任务执行完毕,返回内容:', res); // 输出 {name: '前端路引'}})()
复制代码


生成器函数: async 规范落地之前,JS 还有过一个 生成器函数 也能用来处理异步任务,不过在实际开发中很少使用。


写在最后


JS 的任务调度机制让它拥有大量的异步编程,各式各样的使用方式都有必要了解学习,要不然...嘿嘿...大佬写的代码看不懂~~


文章转载自:前端路引

原文链接:https://www.cnblogs.com/linx/p/18989090

体验地址:http://www.jnpfsoft.com/?from=001YH

用户头像

还未添加个人签名 2025-04-01 加入

还未添加个人简介

评论

发布
暂无评论
Web前端入门:JavaScript async & await 的异步任务进化之路_前端_电子尖叫食人鱼_InfoQ写作社区