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 的任务调度机制让它拥有大量的异步编程,各式各样的使用方式都有必要了解学习,要不然...嘿嘿...大佬写的代码看不懂~~
Web前端入门第 79 问:JavaScript async & await 的异步任务进化之路的更多相关文章
- web前端入坑第五篇:秒懂Vuejs、Angular、React原理和前端发展历史
秒懂Vuejs.Angular.React原理和前端发展历史 2017-04-07 小北哥哥 前端你别闹 今天来说说 "前端发展历史和框架" 「前端程序发展的历史」 「 不学自知, ...
- [每日一题]面试官问:Async/Await 如何通过同步的方式实现异步?
关注「松宝写代码」,精选好文,每日一题 时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...
- JavaScript async/await:优点、陷阱及如何使用
翻译练习 原博客地址:JavaScript async/await: The Good Part, Pitfalls and How to Use ES7中引进的async/await是对JavaSc ...
- [.NET] 利用 async & await 的异步编程
利用 async & await 的异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/5922573.html 目录 异步编程的简介 异 ...
- [.NET] 利用 async & await 进行异步 IO 操作
利用 async & await 进行异步 IO 操作 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6082673.html 序 上次,博主 ...
- 利用 async & await 的异步编程
走进异步编程的世界 - 开始接触 async/await 利用 async & await 的异步编程 async 的三大返回类型 公司技术需求备忘录
- async+await处理异步问题
在编写网页的时候我们常常会遇到异步问题,async+await是es6提出的解决异步的方法,下面我们来看看这个方法怎么实现解决异步的, 大家都知道,setTimeout是一个定时器.他是一个异步执行的 ...
- Atitit. Async await 优缺点 异步编程的原理and实现 java c# php
Atitit. Async await 优缺点 异步编程的原理and实现 java c# php 1. async & await的来源1 2. 异步编程history1 2.1. 线程池 2 ...
- 使用ES6新特性async await进行异步处理
我们往往在项目中会遇到这样的业务需求,就是首先先进行一个ajax请求,然后再进行下一个ajax请求,而下一个请求需要使用上一个请求得到的数据,请求少了还好说,如果多了,就要一层一层的嵌套,就好像有点c ...
- 深入理解协程(三):async/await实现异步协程
原创不易,转载请联系作者 深入理解协程分为三部分进行讲解: 协程的引入 yield from实现异步协程 async/await实现异步协程 本篇为深入理解协程系列文章的最后一篇. 从本篇你将了解到: ...
随机推荐
- thinkphp里__PUBLIC__的使用
1.默认值 __PUBLIC__常量默认指向当前项目根目录下的pulic目录, 例如:www下有一个blog项目目录,blog下一般有application.Home.public.Thinkphp ...
- 29.1K star!免费接入GPT-4/DeepSeek等顶级大模型,这个开源API神器绝了!
嗨,大家好,我是小华同学,关注我们获得"最新.最全.最优质"开源项目和高效工作学习方法 还在为天价API费用发愁?这个开源项目让你免费畅用GPT-4.DeepSeek.Claude ...
- WSL 安装配置 MySQL
在 WSL 安装并配置 MySQL 与在 Ubuntu Server 安装配置 MySQL 一样的步骤.简要记录一下配置的过程. 安装 MySQL 参考微软官方文档[1]安装MySQL. sudo a ...
- 校园圈子系统:Uni-app跨端渲染+TP6实时推送核心逻辑与代码
在TP6中实现实时推送功能,核心逻辑围绕WebSocket服务搭建.用户连接管理.消息路由和性能优化展开.以下是详细的实现步骤和逻辑说明: TP6实时推送核心逻辑 WebSocket服务搭建 使用Wo ...
- C++11 Lambda表达式(匿名函数)详解
使用STL时,往往会大量用到函数对象,为此要编写很多函数对象类.而有的函数对象类只用定义一个对象,而且这个对象也只使用一次,那编写这样一个函数对象就很浪费了.而且有时这定义函数对象类的地方和使用函数对 ...
- 补充停牌的日K数据
问题 从TuShare获取的数据,停牌日是没有数据的,这将会在回测时,不能直接参与账户的净值计算,导致账户的净值以及收益计算不准确. 停盘 股票由于某种消息或进行某种活动引起股价的连续上涨或下跌,由证 ...
- C#程序的内存缓存
C#程序可以使用IMemoryCache.IMemoryCache是.NET Core中内置的一个轻量级缓存实现,可以用于在内存中缓存数据,以提高应用程序的性能和响应速度.它支持通过键值对的方式缓存数 ...
- MySQL的表空间释放
概述 最近为了对 MySQL 数据库磁盘占用瘦身,对一张近100GB表的历史数据进行了 delete 删除,删除了约2/3的数据,删除后发现该表占用的空间并未减少.通过下面语句查看该表的磁盘占用情况: ...
- 自己做的linux动态壁纸软件
自己做的linux动态壁纸软件 https://github.com/dependon/fantascene-dynamic-wallpaper
- consul在netcore中发现服务和运行状况检查
在这篇文章中,我们将快速了解什么是服务发现,使用consul实现一个基本的服务基础设施:使用asp.net核心mvc框架,并使用dns client.net实现基于dns的客户端服务发现. Servi ...