但是对于表达异步流程控制来说有更好的选项,而且在代码风格上可能比长长的promise链更理想。我们可以使用在第三章中学到的generator来表达我们的异步流程控制。
要识别一个重要的模式:一个generator可以yield出一个promise,然后这个promise可以使用它的完成值来推进generator。
考虑前一个代码段,使用generator来表达:
为什么我们要与generator一起使用Promise?不用Promise进行异步generator编码当然是可能的。
Promise是一个可信的系统,它将普通的回调和thunk中发生的控制倒转(参见本系列的 异步与性能)反转回来。所以组合Promise的可信性与generator中代码的同步性有效地解决了回调的主要缺陷。另外,像Promise.all([ .. ])
这样的工具是一个非常美好、干净的方式 —— 在一个generator的一个步骤中表达并发。
那么这种魔法是如何工作的?我们需要一个可以运行我们generator的 运行器(runner),接收一个被yield
出来的promise并连接它,让它要么使用成功的完成推进generator,要么使用拒绝的理由向generator抛出异常。
注意: 这个工具的更丰富注释的版本,参见本系列的 异步与性能。另外,由各种异步库提供的这种运行工具通常要比我们在这里展示的东西更强大。例如,asynquence的runner(..)
可以处理被yield
的promise、序列、thunk、以及(非promise的)间接值,给你终极的灵活性。
于是现在运行早先代码段中的就像这样容易:
实质上,在你程序中的任何拥有多于两个异步步骤的流程控制逻辑的地方,你就可以 而且应当 使用一个由运行工具驱动的promise-yielding generator来以一种同步的风格表达流程控制。这样做将产生更易于理解和维护的代码。