首页 前端开发 Web前端入门第 79 问:JavaScript async & await 的异步任务进化之路

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

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

1、用户交互的点击、输入
2、网络请求的 fetch、ajax、WebSocket
3、资源中的图片、脚本加载
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('异步任务执行完毕,回调函数执行完毕');
});
关于 Promise 可参考之前的文章:Web前端入门第 69 问:JavaScript Promise 提供的方法都使用过吗?

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 还有过一个 生成器函数 也能用来处理异步任务,不过在实际开发中很少使用,在一些多任务的脚手架里面能看到它的身影,使用方法可参考之前的文章:

Web前端入门第 64 问:JavaScript 几种函数定义方式有什么区别?

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

站星网

JS 中异步任务随处可见,比如:1、用户交互的点击、输入2、网络请求的 fetch、ajax、WebSocket3、资源中的..

为您推荐

Web前端入门第 78 问:JavaScript 比较少见的模版字符串用法

在 ES6 之前,JS 的多行字符串一直是开发难题,在处理多行字符串时,各种各样的方案都有~~在 JS 中,如果直接这样写多行字符串:const str1 = '第一行第二行';那浏览器转过来就打脸,分分钟报错:Uncaught S..

Web前端入门第 76 问:JavaScript 鼠标事件(mouse) enter/leave 和 over/out 区别

题外话在考察事件基础的时候,会经常被问及 click、mousedown、mouseup 它们三者执行的先后顺序是怎样的?如果平时没太注意,这细节可能就会忽略,毕竟很少会在同一个元素上面同时绑定这三个事件~~直接上示例:<div ..

35+程序员的转型之路:经济寒冬中的希望与策略

1.继续打工?有一次在网上看到有人讨论一个问题:程序员到了35到40岁,是不是就到了中年危机?是继续找工作,还是自己创业?我在想,核心问题是:你能不能打一辈子工?现实中,合适的工作机会并不多。35、40岁再去找..

Web前端入门第 67 问:JavaScript 中的面向对象编程

此 对象 非彼对象啊,不要理解错了哦~~面向对象编程 这个概念在 Java 编程语言中用得比较多,JS 同时支持 面向对象编程 和 函数式编程。像大名鼎鼎的 React 和 Vue 他们都有两种开发风格,比如:Vue 中的 组合式API ..

Web前端入门第 57 问:JavaScript 数据类型与类型转换

在程序语言中,数据类型是基础,一切程序都是建立在基础数据之上。如果说程序如同万丈高楼平地起,那么数据类型就像沙、石、钢筋、水泥等等最基础的原料。一样的高楼,不同的人,用相同的原料,造的方法也会有千般变..

Web前端入门第 60 问:JavaScript 各种数组定义与数组取值方法

数组可以算是程序里面最常用的数据结构了,但凡网页上任何一个列表数据,基本都是以数组的形式存在,像表格、banner图、菜单列表、商品列表,分类列表等等,在前端领域都是以数组处理。数组的定义JS 的数组花样很多..

Web前端入门第 55 问:JavaScript 严格模式与非严格模式区别

JavaScript 默认是非严格模式的,可以通过 "use strict"; 启用严格模式。此声明语句可以放在 JS 文件顶部,也可以放在函数内部。启用严格模式1、外部脚本在 JS 文件开头声明,内部脚本在 <script> 标签开头声明,声..

Web前端入门第 53 问:JavaScript 的各种调试方法

任何一门编程语言,在学习之前都应该先弄清楚它的调试方法,毕竟没有不挖坑的人类!程序一旦出现问题,第一时间就是找到问题出在哪儿,其次才是拿出解决办法。如果都找不到问题原因,那又何从谈起解决办法呢?如何排..

Web前端入门第 54 问:JavaScript 3 种书写位置及 script 标签的正确存放位置

JS 的代码并没有强制规定放在 HTML 中的某个位置,如果您有使用过开发者工具查看过网页源码,那么您会看到很多 JS 代码都以 .js 文件的形式存放,并且放在了 HTML 文件最后,也就是 </body> 结束标签之前。但如果仔..

Web前端入门第 52 问:JavaScript 的应用领域

截至目前,您应该对前端的 HTML + CSS 应该有了很清楚的认知,至少实现一个静态网页已经完全不在话下了。当然,CSS 功能绝不止这些,一些不太常用的 CSS 相关知识,后续将通过案例进行分享。那么咱们接下来看看 Java..

从零散笔记到结构化知识库:我的文档网站建设之路

我一直有记录笔记的习惯,无论是在工作还是学习中。但随着近年来更换笔记软件、频繁迁移数据,笔记内容逐渐变得零散、分散,缺乏系统性与整体性。为了更好地沉淀和复用这些知识,我决定搭建一个文档网站,对过往的笔..

我的 10 年自学编程之路

为什么每个人都这样匆忙?走进任何一家书店,你都能看到诸如《24小时自学Java》这样的书,可能书名中的Java会变成C、SQL、Ruby、算法等,然后24小时会变成n天或n小时。在亚马逊高级搜索[title: teach, yourself, hou..

回顾我的软件开发经历:我与代码生成器的涅槃之路

前言这是我《回顾我的开发经历》系列的第二篇,聚焦于我与代码生成器的故事。从最初的简单工具到最终演变成一个功能强大的ORM框架,这段经历不仅让我在技术上得到了极大的提升,也让我深刻理解了重构、设计模式和系..

mvc async await异步编程

在mvc中如果要用纯异步请不要使用async和await,可以直接使用Task.Run。在mvc中使用async和await可以让系统开新线程处理Task的代码,同时不必等Task执行结束,就可以同时运行Task之后的代码,加快效率。要注意的是:..

Blazor ServerPrerendered模式OnInitialized{Async}执行两次

创建Blazor应用,刷新页面调试时发现OnInitialized会执行两次。 这里需要注意,进入这个站点的第一个页面的OnInitialized会被执行两次,例如我在浏览器输入URL进去了A页面,那么A页面的OnInitialized会执行两次。然..

深入浅出Oracle-DBA入门、进阶与诊断案例免费下载

目前市场上的Oracle书籍普遍存在的问题是模式单一,要么只讲基础知识,要么侧重代码编程实例,要么针对具体的版本特性(Oracle8i/Oracle9i/Oracle10g等),要么缺少实践应用检验,很少能对Oracle相关知识进行全面深..

.NET async await最佳实践

.NET 中的 async/await 是用于简化异步编程的关键工具。它允许你以一种类似于同步代码的方式编写异步代码,使得异步操作更加易于理解和维护。在使用 async 和 await 进行异步编程时,以下是一些 .NET 中的最佳实践:..

严澜:数据挖掘入门—分词

谷歌4亿英镑收购人工智能公司DeepMind,百度目前正推进“百度大脑”项目,腾讯、阿里等各大巨头也在积极布局深度学习。随着社会化数据大量产生,硬件速度上升、成本降低,大数据技术的落地实现,让冷冰冰..

C#中await/async异步编程采坑—async方法可能会同步执行

前言在C# 5.0和.NET 4.5中,引入了基于await/async的异步编程模式,也称为“基于任务的异步编程模型 (TAP) ”。它有效地避免了异步任务回调嵌套的地狱,而且非常易于使用,但是深度理解它却比学会使用它要困难得多。..

在线文档生成工具Docusaurus入门:如何安装

Docusaurus简介Docusaurus是一个静态网站生成器,它是用 React 写的源代码,然后编译成静态的 HTML + CSS + JS。支持 Markdown语法,并且Markdown 是用的mdx,也就是支持 jsx 语法的Markdown,无缝结合 React, 还可..

发表回复

返回顶部

微信分享

微信分享二维码

扫描二维码分享到微信或朋友圈

链接已复制