You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
asyncfunctionasyncFunc(){constwriter=openFile('someFile.txt');writer.write('hello');// don’t waitwriter.write('world');// don’t waitawaitwriter.close();// wait for file to close}
综述
现在以下几种
async
函数的用法都是可行的。Async函数声明:
Async函数表达式:
Async方法定义:
Async箭头函数:
Async函数通常返回的是 Promise:
只有操作符
await
可以放在 Async 函数里用来处理返回的 Promise 对象结果。所以await
的处理结果随着 Promise 的状态不同而不同。简单处理一个异步结果:
顺序处理多个异步结果:
平行处理多个异步结果:
处理错误异常:
理解
async
函数在我解释
async
函数之前,我想通过把Promises
和generator
结合起来,用看起来像同步代码的方式去模拟异步方式。对于处理获取一次性结果的异步函数,
Promises
是目前最流行的方式。下面是一个使用fetch
方法获取文件的示例:co
是一个基于Promises
和generator
的实现,也能够让你以书写同步代码的方式来实现上面的示例。co
在generator
回调函数中每次检测到一个带有yield
操作符的方法,就会产生一个Promise
对象,co
会先暂停回调代码的执行,直到Promise
对象的状态发生变化再继续执行。无论Promise
的状态为resolved
或者rejected
,yield
都会将相应的结果值返回。详细说明一下
async
函数的执行过程:async
函数在开始执行的时候,通常都是返回一个Promise
对象return
或者throw
直接完成执行过程。也可以使用await
暂时完成执行过程,然后根据情况再继续执行Promise
对象then
和catch
中的callback只有在当前所有代码执行完毕之后,才会被执行。从下面的输出结果可以看出函数asyncFunc
的返回值等到所有代码包括循环逻辑都执行完毕之后,才最终得以被输出使用
return
去Resolve
一个async
函数状态,是一种很标准的操作方式。这意味着你可以:Promise
对象类型的值,作为Resolve
状态的参数值Promise
对象代表了当前async
的函数状态使用
await
的若干贴示使用
async
函数最常犯的一个错误就是忘记添加await
关键字,在下面示例中value
被指向了一个Promise
对象,但它可能并不是你想要的结果:await
可以感知到后面跟的异步函数是否返回了结果值,然后它就可以告诉调用者当前的异步函数是否已经执行完毕了。例如在下面的示例中,await
可以确保step1()
执行完之前,不会招待foo()
的剩余逻辑代码:有时候你仅仅是想触发一个异步函数计算,并不想知道它会何时完成。在下面示例中,我们并不关心写文件的操作何时完成,只要它们是按正确的顺序执行就可以了。最后一行的
await
只是为了确保关闭写文件的操作能被成功执行即可。多个
await
异步函数是顺序执行的关系,想要它们同时执行就得使用Promise.all()
了:async
在回调函数中的应用有一个需要知道的限制是,
await
操作符只会影响async
函数的直接作用域环境。因此,你不能在async
函数内的回调函数中使用await
,这也会让那些基于callback
的方法变得非常难于理解。Array.prototype.map()
下面的示例是想下载若干url并返回其内容:
像上面这种在普通的箭头函数中使用
await
根本无法运行,会抛出语法错误。那我们应该怎么用,像下面这样吗:输出结果:
你会发现代码中有两个问题:
Promise
对象的数组,并不是我们期望的包含resolve
返回值的数组await
只能暂停箭头回调函数里的httpGet()
,map
本身的回调函数执行完成之后,并不能影响外层的downloadContent ()
也执行完成我们用
Promise.all()
来修复这两个问题,把返回的 包含两个Promise
对象的数组 转换成 包含两个数组元素的Promise
对象,看如下示例:输出结果:
OK,现在输出结果是正确的了。但是这段代码还是有一点点低效的地方需要改进,
downloadContent ()
函数里首先用await
展开了Promise.all()
的返回结果,后面又用return
包装了一次,其实我们用return
直接返回Promise.all()
即可:Array.prototype.forEach()
我们这次换成
forEach()
方法来模拟输出若干文件内容。很显然,下面的示例会抛出语法错误,因为你不能在普通的箭头函数中直接使用await
:那我把代码修改成如下:
这次代码倒是运行了,但是
httpGet()
方法返回resolve
状态的操作是异步的,也就是说当forEach()
方法已经返回之后,它的callback
还并没有执行完成。修复此问题,只需要将代码做一下更改:这段示例中的
httpGet()
执行顺序是线性的,每一次的调用必须要等待上一次执行完毕。如果想要改成并行的执行顺序,就得用Promise.all()
了:map()
方法创建了一个Promise
对象数组。我们并不关心这几个Promise
对象的履行结果,只要它们履行了即可。也就是loginContent()
方法执行完成就可以了。在这个示例中除非把Promise.all()
直接返回,否则此函数的结果只会包含若干`undefined。使用
async
函数的若干贴示async
函数的基础就是Promise
,所以充分理解下面的示例非常重要。尤其是在那些没有使用Promise
机制的老代码中使用async
函数时,你可能除了直接使用Promise
之外没有别的选择。下面是一个在
XMLHttpRequest
中使用Promise
的示例:XMLHttpRequest
的 API 设计都是基于 callback 的。使用async
函数就意味着你要在内层回调函数里使用return
和throw
返回Promise
对象的状态,但这肯定是不可能的。因此,在这情况中使用async
的风格就是:Promise
直接构建一个异步的基元async
函数来使用这些基元在一个模块或者 script 的顶级作用域中使用
await
,可以像下面这样:或者
或者
不用太担心那些未处理
rejections
,以前这种情况可能都是静默失败,不过现在大多数的现代浏览器都会抛出一个未处理的异常:The text was updated successfully, but these errors were encountered: