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实现异步协程 本篇为深入理解协程系列文章的最后一篇. 从本篇你将了解到: ...
随机推荐
- 20241105,LeetCode 每日一题,用 Go 实现两数之和的非暴力解法
题目 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标. 你可以假设每种输入只会对应一个答案,并且你不能 ...
- 太喜欢啦,浏览器中的SQL神器:WhatTheDuck让CSV分析像聊天一样简单!
嗨,大家好,我是小华同学,关注我们获得"最新.最全.最优质"开源项目和高效工作学习方法 基于DuckDB的轻量级Web应用 | 完全浏览器端运行 | 零数据泄露风险 | 支持复杂S ...
- MySQL的基本语法(增,删,改,查)
MySQL的基本语法(增,删,改,查) MySQL中的(增)操作 创建数据库 CREATE DATABASE 库名; 例如: CREATE DATABASE db; 创建一个名为db的数据库. 创建列 ...
- Spring创建Bean的三种方式及Bean的生命周期
目录 Spring创建Bean的三种方式及Bean的生命周期 Spring创建Bean的三种方式 第一种方式:使用默认构造函数创建 第二种方式:使用普通工厂中的方法创建对象 第三种方式:使用工厂中的静 ...
- Java--通过jdbc访问mysql数据库(mysql v8.0.11)
由于mysql的更新,原来的连接数据库方法改变了 参考:http://www.cnblogs.com/rainbow70626/p/9005852.html package demo; import ...
- 【代码】百度语音API|Python|文本朗读
百度语音合成官方教程_AI开放平台 百度语音合成官方demo_github.com 简单地写了一个按段落朗读文本的demo:DEMO链接_gitee.com. 有时候会请求不到数据,不知道是网络原因还 ...
- idea中代码提交流程(git版)
本文主要分享一下如何通过idea通过git拉取项目并且进行编辑后提交到远程master上进行合并. 1.安装idea编译器,我们用的是社区版本2021.1,安装步骤略过. 2.打开idea,点击Fil ...
- DP 动态规划初识
前面的 HMM 中参数求解, 都会用到动态规划, 全是各种概率公式, 是有一些抽象, 今天决定举个一波简单的栗子, 帮助理解DP 把一个大问题,不断划分为更小的子问题来求解的这种方式, 就是动态规划. ...
- 深入浅出:AST 技术的应用与实践
@charset "UTF-8"; .markdown-body { line-height: 1.75; font-weight: 400; font-size: 15px; o ...
- 使用 frp 进行内网穿透
frp 是一个开源的内网穿透工具,可以使外网设备访问内网防火墙后的设备/服务器. 比如可以买一个 99元/年 的阿里云低配 ECS,然后把自己相对高配的旧电脑放在家里. 家里的旧电脑通过 frp 连上 ...