上一节,为了优化异步写法,我们写了一个generatorfunction和promise的组合版本,看起来不错。唯一遗憾的是我们每次都需要写run函数,并在run函数中构建生成函数其实浏览器为此设计了特殊的语法,我们不再需要构建run函数,因为这个函数有已在浏览器中实现,格式如下:functionsquareAsync(x){returnnewPromise(resolve=>{setTimeout(()=>resolve(x*x),1000+Math.random()*2000)})}asyncfunctionfoo(){//这句话对应function*foo()vara=awaitsquareAsync(5)//await对应yieldconsole.log(a)returnPromise.reject(3)}//>Promise{}//25//3foo().catch(val=>console.log(val))这里的asyncfunctionfoo()就像是浏览器在run中运行foo,传过去比较方便此时foo函数的参数。同样,await后面跟着promise,函数运行时遇到await会暂停,直到达到promise的执行结果再继续执行。这里的promise不再需要调用then来获取求值结果,直接相当于一个赋值语句。async不是关键字,必须和function一起使用才有效。注意这里函数的返回结果是一个promise,所以可以在foo之后调用then/catch来接收foo的返回结果。举几个例子,在前面学习Promise的时候,我们给出了一个加载图片的例子,串行加载,串行显示asyncfunctionshowStory(storyUrl){varstory=awaitgetJSON(storyUrl)for(varchapterUrlofstory.chapterUrls){var章节r=awaitgetJSON(chapterUrl)//一一加载addContentToPage(chapter)}}并行加载,串行显示asyncfunctionshowStory(storyUrl){varstory=awaitgetJSON(storyUrl)varchapterPromises=story.chapterUrls.map(getJSON)//同时加载for(varchapterPromiseofchapterPromises){varchapter=awaitchapterPromiseaddContentToPage(chapter)}}我们来写上一节读取文件名的第四个版本,异步版本的函数constfs=require('fs')constfsp=fs.promisesasyncfunctionlistAllFiles(path){varresult=[]varstat=awaitfsp.stat(path)if(stat.isFile()){return[path]}else{varentries=awaitfsp.readdir(path,{withFileTypes:true})for(letentryofentries){//这里不能使用forEach。因为forEach不能连接异步函数varfullPath=path+'/'+entry.namevarfiles=awaitlistAllFiles(fullPath)//①result.push(...files)}returnresult}}listAllFiles('.').then(console.log)分析,如果这样写,效率可能没有以前那么高,因为第一个文件夹在①处加载完后才能加载第二个,此时我们可以优化为并行加载/串行显示:constfs=require('fs')constfsp=fs.promisesasyncfunctionlistAllFiles(path){varresult=[]varstat=awaitfsp.stat(path)if(stat.isFile()){return[path]}else{varentries=等待fsp.readdir(path,{withFileTypes:true})varentryPromises=entries.map(entry=>{varfullPath=path+'/'+entry.namereturnlistAllFiles(fullPath)})for(letentryPromiseofentryPromises){varfiles=awaitentryPromiseresult.push(...files)}returnresult}}listAllFiles('.').then(console.log)这种方法是性能比较高的,同时等待cpu也是可以的运行其他程序,但是还有改进的余地,因为这个方法是串行等待每个任务,即使第二个完成,第一个没有完成,第二个也不能这样处理,如图图中黑色部分是等待时间,蓝色部分是执行时间,比如:最长时间等待10s,执行时间1s,①一共用了15s,②只用了11s,因为for循环是这里用了,这里也用了promise都不起作用,所以这里最好的办法就是回调函数constfs=require('fs')constfsp=fs.promisesasyncfunctionlistAllFiles(path){varresult=[]varstat=awaitfsp.stat(path)if(stat.isFile()){return[path]}else{varentries=awaittfsp.readdir(path,{withFileTypes:true})varentryPromises=entries.map((entry,i)=>{varfullPath=path+'/'+entry.name返回listAllFiles(fullPath).then(files=>{result[i]=files})})varentryValues=awaitPromise.all(entryPromises)return[].concat(...result)}}listAllFiles('.').then(console.log)实现了上图中②的效果,即同时开发所有任务