异步函数async

article/2025/9/18 3:44:51

什么是同步异步

在最新的ES7(ES2017)中提出的前端异步特性:async、await。
在了解async和await之前得先明白什么是同步函数,什么是异步函数。

  • 同步函数:当一个函数是同步执行时,那么当该函数被调用时不会立即返回,直到该函数所要做的事情全都做完了才返回。比如说在银行排队办理业务,要等到前面一个人办完才能到下一个。
  • 异步函数:如果一个异步函数被调用时,该函数会立即返回尽管该函数规定的操作任务还没有完成。比如一个人边吃饭,边看手机,边说话,就是异步处理的方式。

async

async从字面意思上很好理解,是异步的意思,async用于申明一个function是异步的,函数返回的是一个promise。

  • async作为关键字放到函数前面,用于表示函数是一个异步函数。该函数的执行不会阻塞后面代码的执行。
  • async函数返回的是一个promise对象,可以调用then方法获取到promise的结果值。
async function f() { return 1; 
} 
f().then((res) => { console.log(res) 
}) //1

async函数会返回一个promise对象,如果function中返回的是一个值,async直接会用Promise.resolve()包裹一下返回。

await

await有等待的意思,等待一个异步方法执行完成。

  • await关键字只能放async函数里面。 而async函数里不是必须有await。
  • await关键字的返回结果就是其后 promise执行的结果值,是resolved或者 rejected后的值。
function getSomething() { return "something"; 
} async function testAsync() { return Promise.resolve("hello async"); 
} async function test() { const v1 = await getSomething(); const v2 = await testAsync(); console.log(v1, v2); 
} 
test(); // something hello async 
  • 为什么await关键词只能在async函数中用

await操作符等的是一个返回的结果,那么如果是同步的情况,那就直接返回了。

那如果是异步的情况呢,异步的情况下,await会阻塞整一个流程,直到结果返回之后,才会继续下面的代码。

阻塞代码是一个很可怕的事情,而async函数,会被包在一个promise中,异步去执行。所以await只能在async函数中使用,如果在正常程序中使用,会造成整个程序阻塞,得不偿失。

async/await

异步代码就像写同步代码一样,也避免了回调地狱。

  • 串行:等待前面一个await执行后接着执行下一个await,以此类推
async function asyncAwaitFn(str) {return await new Promise((resolve, reject) => {setTimeout(() => {resolve(str)}, 1000);})
}const serialFn = async () => { //串行执行console.log(await asyncAwaitFn('string 1'));console.log(await asyncAwaitFn('string 2'));console.timeEnd('serialFn ')
}serialFn();

在这里插入图片描述

  • 并行:将多个promise直接发起请求(先执行async所在函数),然后再进行await操作
async function asyncAwaitFn(str) {return await new Promise((resolve, reject) => {setTimeout(() => {resolve(str)}, 1000);})
}
const parallel = async () => { //并行执行const parallelOne = asyncAwaitFn('string 1');const parallelTwo = asyncAwaitFn('string 2')//直接打印console.log(await parallelOne)console.log(await parallelTwo)console.timeEnd('parallel')
}
parallel()

在这里插入图片描述

async、await错误处理

在Promise中当请求reject的时候我们可以使用catch。为了保持代码的健壮性使用async、await的时候我们使用try catch来处理错误。

async function catchErr() {try {const errRes = await new Promise((resolve, reject) => {setTimeout(() => {reject("http error...");}, 1000););//平常我们也可以在await请求成功后通过判断当前status是不是200来判断请求是否成功// console.log(errRes.status, errRes.statusText);} catch(err) {console.log(err);}
}
catchErr(); //http error...

虽然async、await也使用到了Promise但是却减少了Promise的then处理使得整个异步请求代码清爽了许多。

前面扯了这么多,也是时候回到正题了,我们先来看下面的一个例子。
我们需要做一个功能,在页面加载的时候实现查询三组数据:查询用户、查询朋友、查询图片。

class Api {constructor () {this.user = { id: 1, name: 'test' }this.friends = [ this.user, this.user, this.user ]this.photo = 'not a real photo'}getUser () {return new Promise((resolve, reject) => {setTimeout(() => resolve(this.user), 200)})}getFriends (userId) {return new Promise((resolve, reject) => {setTimeout(() => resolve(this.friends.slice()), 200)})}getPhoto (userId) {return new Promise((resolve, reject) => {setTimeout(() => resolve(this.photo), 200)})}throwError () {return new Promise((resolve, reject) => {setTimeout(() => reject(new Error('Intentional Error')), 200)})}
}

在上面定义了API的类,里面写了三个封装的查询接口。现在要依次执行那三个操作。
第一种方法:Promises的嵌套

function callbackHell () {const api = new Api()let user, friendsapi.getUser().then(function (returnedUser) {user = returnedUserapi.getFriends(user.id).then(function (returnedFriends) {friends = returnedFriendsapi.getPhoto(user.id).then(function (photo) {console.log('callbackHell', { user, friends, photo })})})})
}

从上面可以看出,这代码块很简单,但它有很长、很深的嵌套。

这只是简单的函数内容,但在真实的代码库中,每个回调函数可能会很长的代码,这就可能会导致代码变得庞大难读懂。处理此类代码,在回调内的回调中使用回调,通常称为“回调地狱”。

更糟糕的是,没有错误检查,因此任何回调都可能作为未处理的resove/reject而失败。
第二种方法:Promises链

function promiseChain () {const api = new Api()let user, friendsapi.getUser().then((returnedUser) => {user = returnedUserreturn api.getFriends(user.id)}).then((returnedFriends) => {friends = returnedFriendsreturn api.getPhoto(user.id)}).then((photo) => {console.log('promiseChain', { user, friends, photo })})
}

Promises的一个不错的功能是,可以通过在每个回调中返回另一个Promises来链接它们。这样,我们可以将所有回调保持在相同的缩进级别。我们还可以使用箭头函数来简化回调函数的声明。

当然,此变体比第一种易于阅读,并且有更好的顺序感,但是,仍然很冗长且看起来复杂。
第三种方法 async/await

async function asyncAwaitIsYourNewBestFriend () {const api = new Api()const user = await api.getUser()const friends = await api.getFriends(user.id)const photo = await api.getPhoto(user.id)console.log('asyncAwaitIsYourNewBestFriend', { user, friends, photo })
}

现在看起来,好多了。

在Promises之前调用“await”关键字暂停函数的流程,知道Promises被解决,并将结果分配给等号左侧的变量。这样,我们可以对异步操作流程进行编程,就好像它是普通的同步命令系列一样。

上面的例子比较简单实现,下面我们继续讲下一个例子。

现在有一个功能,要获取一个用户的朋友的朋友列表。

第一种方法:递归Promises循环:

function promiseLoops () {  const api = new Api()api.getUser().then((user) => {return api.getFriends(user.id)}).then((returnedFriends) => {const getFriendsOfFriends = (friends) => {if (friends.length > 0) {let friend = friends.pop()return api.getFriends(friend.id).then((moreFriends) => {console.log('promiseLoops', moreFriends)return getFriendsOfFriends(friends)})}}return getFriendsOfFriends(returnedFriends)})
}

我们正在创建一个内部函数,该函数已递归的方式来获取Promises,知道列表为空。虽然它具有完整的功能,但这只是对于简单的任务来说。

第二种方法:async/await循环

async function asyncAwaitLoops () {const api = new Api()const user = await api.getUser()const friends = await api.getFriends(user.id)for (let friend of friends) {let moreFriends = await api.getFriends(friend.id)console.log('asyncAwaitLoops', moreFriends)}
}

无需编写任何递归的Promises闭包。只是一个循环。

同步操作
逐个列出每个用户的朋友的朋友有点慢?为什么不并行进行呢?

我们依然可以使用async和await来解决。

async function asyncAwaitLoopsParallel () {const api = new Api()const user = await api.getUser()const friends = await api.getFriends(user.id)const friendPromises = friends.map(friend => api.getFriends(friend.id))const moreFriends = await Promise.all(friendPromises)console.log('asyncAwaitLoopsParallel', moreFriends)
}

并并行运行操作,就要形成运行的Promises数组,并将其作为参数传递给Promise.all()。这将返回一个等待的Promise,一旦所有操作完成,就会返回。


http://chatgpt.dhexx.cn/article/FDu6IVCd.shtml

相关文章

异步(async、await)

同步与异步 同步:如果一个程序调用某个方法,等待其执行所有处理后才继续执行,我们就称这样的方法是同步的,这是默认的形式异步:异步的方法在处理完成之前就返回到调用方法,C#的async/await特性可以创建并使…

async/awiat和promise之间的区别

今天看到了一段代码 async function async1() {console.log(async1 start);await async2();console.log(async1 end); } async function async2() {console.log(async2); } console.log(script start); setTimeout(function() {console.log(setTimeout); }, 0) async1(); new …

什么是异步

文章目录 前言一、异步是什么?二、举个例子来理解异步 1.异步最典型的例子就是“回调函数”总结 前言 在vue的过程中,我们一定会遇到诸如: function(参数).then(res>{}) 形式的代码。到底怎么编译执行的呢 &#x…

Spring Boot 基础学习之(五)页面通过自定义LocaleResolver组件实现网页页面的的中英文转换

本次项目所有能够使用的静态资源可以免费进行下载 静态资源 在前端网页,是不是看见过这样的功能 基础网页:中文表示 点击下面的English 按钮网页显示文字开始切换 通过功能性按钮实现中英文切换,在浏览器中,都带着一个功能叫翻…

网页中文转英文(国际化)

背景: 我的项目是已经完成的项目,因为要拓展海外市场,需要支持英文。 采用的方式是添加配置文件,见下文详细步骤。 本文基本转自:http://blog.csdn.net/wuhawang/article/details/52228589 在他的基础上给大家一点提示…

英语数字转换器

英语数字转换器 STL中map,stack和string的运用 描述: 在这个问题中,将用英语给你一个或多个整数。你的任务是将这些数字转换成整型表示。数字范围从-999,999,999到999,999,999.下面是你的程序必须考虑的详尽的英语单词表: neg…

Unity 中英文转换

在Resources下创建文件夹LanguageTxt,再其创建“Chinese.txt”及“English.txt”(记得保存文本时选择UTF-8) Chinese.txt Btn:这是一个按钮 English.txt Btn:This is a button 在Scripts下创建“LanguageManager.cs”及“UIText.cs” L…

SAP中英文转换--中文转英文

中文转英文-函数:CONVERSION_EXIT_CUNIT_INPUT CALL FUNCTION ‘CONVERSION_EXIT_CUNIT_INPUT’ EXPORTING input “输入的中文单位 IMPORTING output “输出的英文单位 效果图:

SAP 中英文转换-英转中

英文转中文-函数:CONVERSION_EXIT_CUNIT_OUTPUT CALL FUNCTION ‘CONVERSION_EXIT_CUNIT_OUTPUT’ EXPORTING input “输入的英文单位 IMPORTING output “输出的中文单位

将数字转换为中文

功能需求 做公司项目遇到一个有关交易金额(合同签订书)的内容,需要将查询出来的交易金额转化为中文数字,例如:壹拾捌万伍仟元整(185000.00) 需求分析 因为合同书中的数据都是动态的&#xff0c…

Java 16进制报文转换中英文报文(通过字节转换)

最近在搞这个16进制报文,网上找了很多地方,解出来的结果不是乱码就是报错,干脆自己写了。 大概是这样的,16进制的报文大家都知道是什么样子 例如: 3C E4 BA A4 E6 98 93 E6 88 90 E5 8A 9F EF BC 81 3E 20 3C 42 61 6B 31 2F 3E 因为其中包…

通过C#进行中英文转换

通过C#进行中英文转换 编写相应语言的XML文件&#xff0c;添加xml文件 ChineseSimplified.xml文件内容 <?xml version"1.0" encoding"GB2312" ?> <Softimite Language"12"><Form><Name>LoginForm</Name><…

【Adobe After Effects中英文转换2019——2023版】

** Adobe After Effects中英文转换2019——2023版 ** 如果是默认安装的软件&#xff0c;在桌面右击AE图标&#xff0c;点击打开文件所在位置&#xff0c;来到软件安装目录 C:\Program Files\Adobe\Adobe After Effects 2023\Support Files 找到AMT文件夹 点击进入&#xf…

在线中英文符号转换工具

在线中英文符号转换工具 在线中英文符号转换工具 将中文符号转换成英文符号或将英文符号转换成中文符号&#xff0c; 将单引号‘’都转换成’&#xff0c; 将双引号“”都转换成" 将中括号【】转换成[]&#xff0c; 将大括号&#xff5b;&#xff5d;转换成{} 将逗号&…

英文表格如何快速转换为中文?

今天跟大家分享一下英文表格如何快速转换为中文&#xff1f; 1.首先打开Excel文件&#xff0c;选中要翻译的单元格&#xff0c;点击【DIY工具箱】 ​ 2.点击【翻译】 3.选择【有道翻译】 4.将翻译语言设置为中文&#xff0c;然后点击【确定】 5.鼠标点击一个合适的单元格作为翻…

英文转换-在线英文批量转换器免费

英文转换&#xff0c;怎么找到好的英文转换器&#xff1f;今天给大家分享一款免费批量的英文转换器汇集了世界最好的几个翻译平台&#xff08;百度/谷歌/有道&#xff09;&#xff0c;为什么这么多人使用它&#xff1f;首先第一点翻译质量高&#xff0c;选择性多。第二点可以批…

php 英文转中文,中文转换成英文

[php]代码库/** * 中文转换成英文 */ function pinyin($_String, $_Codegb2312){ $_DataKey "a|ai|an|ang|ao|ba|bai|ban|bang|bao|bei|ben|beng|bi|bian|biao|bie|bin|bing|bo|bu|ca|cai|can|cang|cao|ce|ceng|cha". "|chai|chan|chang|chao|che|chen|cheng|c…

C#小知识之中英文转换、去空格

一、中英文转换 1、安装NPinYin 2、编写代码 string str "这里是测试的中文字符串"; string str1 Pinyin.GetChineseText(str); string str2 Pinyin.GetInitials(str); string str3 Pinyin.GetPinyin(str);Console.WriteLine("取和拼音相同的汉字列表&…

Qt 语言家实现中英文切换(解决纯代码添加部件的中英文转换问题)

Qt 语言家实现中英文切换&#xff08;解决纯代码添加部件的中英文转换问题&#xff09; 关于.ts和.qm文件的生成&#xff0c;更新翻译、发布翻译等步骤就不多说了&#xff0c;其他博主有大量的描述。 现在我要解决的是中英文未完全转换的问题如下图&#xff1a; 如上图所示&a…

系统的学习网络编程,这篇就够了!(来收藏夹里吃灰)

主机字节序和网络字节序&#xff1a; 在32位机器上&#xff0c;累加器一次能装载4个字节&#xff0c;这四个字节在内存中排列顺序将影响它被累加器装载成的整数的值 大端字节序&#xff08;网络字节序&#xff09;&#xff1a;一个整数的高位字节存储在内存的低地址处 小端字节…