前言在异步处理方案中,最简洁优雅的就是async函数(以下简称A函数)。经过必要的block封装后,A函数可以像同步操作一样聚合多个相关的异步操作,使得它们之间的关系更清晰,流程更简洁,调试更方便。它本质上是Generator函数的语法糖。通俗地说,就是使用G函数进行异步处理的加强版。如果你尝试去学习A函数,你必须要有Promise基础,你还必须了解Generator函数。如果需要,可以查看扩展部分。为了直观感受A函数的魅力,下面使用Promise和A函数进行同样的异步操作。异步的目的是获取用户的消息列表,需要分页,由后台控制。具体操作是:首先获取消息总数,然后修正当前要显示的页数(每次切换到不同的页面,总数可能会发生变化),最后传递参数并获取相应的数据.lettotalNum=0;//Totalcommentsnumber.letcurPage=1;//Currentpageindex.letpageSize=10;//Thenumberofcommentdisplayedinonepage.//主要代码使用A函数。asyncfunctiondealWithAsync(){totalNum=awaitgetListCount();console.log('Getcount',totalNum);if(pageSize*(curPage-1)>totalNum){curPage=1;}returngetListData();}//使用Promise主代码.functiondealWithPromise(){returnnewPromise((resolve,reject)=>{getListCount().then(res=>{totalNum=res;console.log('Getcount',res);if(pageSize*(curPage-1)>totalNum){curPage=1;}returngetListData()}).then(resolve).catch(reject);});}//开始执行dealWithAsync函数。//dealWithAsync().then(res=>{//console.log('GetData',res)//}).catch(err=>{//console.log(err);//});//开始执行dealWithPromise函数。//dealWithPromise().then(res=>{//console.log('GetData',res)//}).catch(err=>{//console.log(err);//});functiongetListCount(){returncreatePromise(100).catch(()=>{throw'Getlistcounterror';});}functiongetListData(){returncreatePromise([],{curPage:curPage,pageSize:pageSize,}).catch(()=>{throw'Getlistdataerror';});}functioncreatePromise(data,//Rebackdataparams=null,//RequestparamsisSucceed=true,timeout=1000,){returnnewPromise((resolve,reject)=>{setTimeout(()=>{isSucceed?resolve(data):reject(data);},timeout);});}对比dealWithAsync和dealWithPromise这两个简单的函数,可以直观的发现,使用A函数,除了await关键字,类似于同步代码没有区别。但是使用Promise需要按照规则添加很多包裹链操作,导致回调函数过多,不够简单。另外,这里将各个异步操作分开,并指定了每次成功或失败时传输的数据,更贴近实际开发。1启示1.1形式函数也是函数,所以具有普通函数应有的性质。但是在形式上有两点不同:首先,在定义A函数的时候,在function关键字之前需要加上async关键字(异步的意思),表示这是一个A函数。二是在A函数内部可以使用await关键字(意思是等待),意思是后面的结果会被当作异步操作,等待它完成。这里有几种定义它的方法。//declarativeasyncfunctionA(){}//表达式letA=asyncfunction(){};//作为对象属性leto={A:asyncfunction(){}};//作为对象属性的简写leto={asyncA(){}};//箭头函数leto={A:async()=>{}};1.2返回值执行函数A,固定返回一个Promise对象。获取到对象后,可以监听设置成功或失败时的回调函数。如果函数执行成功并结束,则返回的P对象的状态将从waiting变为successful,并输出return命令的返回结果(否则为undefined)。如果函数在执行过程中失败,JS会认为A函数已经执行完毕,返回的P对象的状态会由waiting变为failure,并输出错误信息。//成功执行caseA1().then(res=>{console.log('执行成功',res);//10});asyncfunctionA1(){letn=1*10;returnn;}//执行失败CaseA2().catch(err=>{console.log('执行失败',err);//iisnotdefined.});asyncfunctionA2(){letn=1*i;returnn;}1.3await只存在于A函数内部只能使用await命令,存在于A函数内部的普通函数不能。引擎会统一把await之后后面的值当做一个Promise,调用Promise.resolve()将不是Promise对象的值进行转换。即使这个值是一个Error实例,在转换之后,引擎仍然认为它是一个成功的Promise,它的数据是一个Error实例。当函数执行到await命令时,会暂停执行,等待后续的Promise结束。如果P对象最后成功了,它会返回一个成功的返回值,相当于把awaitxxx换成了返回值。如果P对象最后失败了,错误没有被捕捉到,引擎会直接停止执行A函数,并将返回对象的状态变为失败,并输出错误信息。***,A函数中的returnx表达式相当于returnawaitx的缩写。//成功执行caseA1().then(res=>{console.log('执行成功',res);//大约两秒后输出100。});asyncfunctionA1(){letn1=await10;letn2=awaitnewPromise(resolve=>{setTimeout(()=>{resolve(10);},2000);});returnn1*n2;}//执行失败案例A2().catch(err=>{console.log('执行失败',err);//大约两秒后输出10。});asyncfunctionA2(){letn1=await10;letn2=awaitnewPromise((resolve,reject)=>{setTimeout(()=>{reject(10);},2000);});returnn1*n2;}2入侵2.1子序列和并发对于JS语句中存在的await命令(for,while等),引擎也会在遇到时暂停执行。这意味着可以使用循环语句直接处理多个异步。下面是两个处理次级的例子。A函数在处理连续异步的时候特别简洁,整体上和同步代码没什么区别。//A1和A2这两个方法的行为结果是一样的,都是每秒输出10,输出3次。asyncfunctionA1(){letn1=awaitcreatePromise();console.log('N1',n1);letn2=awaitcreatePromise();console.log('N2',n2);letn3=awaitcreatePromise();console.log('N3',n3);}asyncfunctionA2(){for(leti=0;i<3;i++){letn=awaitcreatePromise();console.log('N'+(i+1),n);}}functioncreatePromise(){returnnewPromise(resolve=>{setTimeout(()=>{resolve(10);},1000);});}下面是三个处理并发的例子。A1函数使用Promise.all异步生成聚合。虽然简单,但是灵活性降低了。只有成功和失败两种情况。A3函数相对于A2只是为了说明如何使用数组遍历方法使用async函数。重点是对A2函数的理解。A2函数使用循环语句,其实是二次获取每一个异步值,但是在整体时间上是相当并发的(这个需要好好理解)。因为在一开始创建reqs数组的时候,每一个异步都已经执行过了,虽然是一个一个的获取,但是总的耗时与遍历顺序无关,总是等于异步最耗时(不考虑遍历、执行等耗时)。//A1、A2、A3这三个方法的行为结果是一样的,都在大约一秒后输出[10,10,10]。asyncfunctionA1(){letres=awaitPromise.all([createPromise(),createPromise(),createPromise()]);console.log('Data',res);}asyncfunctionA2(){letres=[];letreqs=[createPromise(),createPromise(),createPromise()];for(leti=0;i
