当前位置:嗨网首页>书籍在线阅读

15-向前一步和退后两步

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

14.4.1 向前一步和退后两步

大家可能(相当合理)会觉得在理解异步执行时遇到了很多麻烦,来简化一下这些麻烦:除了了解了生成器所带来的额外复杂度和把一般内容转化成promise和grun的方法之外,貌似又回到了起点。而事实上,在 theFutureIsNow 函数中,有一点不分好坏的排斥。它更容易阅读和编写,而开发人员也正在从异步执行中受益,但并非受益于它的全部内容。这里就有一个尖锐的问题了:“如果并行地去读取三个文件中的内容,效率会更高吗?”这个问题的回答取决于很多因素,比如,JavaScript引擎是如何实现的,在用什么操作系统,以及所使用的文件系统。不过可以暂时把这些复杂的因素抛到一边,识别出其中的关键部分,那就是不管用什么样的顺序读取这三个文件,可以明确知道的是,运行效率的提升是因为允许这些文件的读操作可以并行发生。而这也是生成器运行器使人自鸣得意,误以为问题就这么被解决了的原因:这样写函数,是因为它看起来简单且直接。

问题(假设这里有问题)很好解决。 Promise 提供了一个叫作all的方法,它会在数组中所有promise都被解决后才被调用,并且它有可能会同时执行异步代码。我们需要做的仅仅是修改函数,让它使用 Promise.all

function* theFutureIsNow() {
   const data = yield Promise.all([
      nfcall(fs.readFile, 'a.txt'),
      nfcall(fs.readFile, 'b.txt'),
      nfcall(fs.readFile, 'c.txt'),
   ]);
   yield ptimeout(60*1000);
   yield nfcall(fs.writeFile, 'd.txt', data[0]+data[1]+data[2]);
} 

Promise.all 返回的promise中会提供一个包含了所有被满足的promise值的数组,顺序跟数组中原来的promise顺序保持一致。即便c.txt可能在a.txt之前被读取, data[0] 始终会保持a.txt的内容,而 data[1] 则始终存储c.txt的内容。

本章节中需要大家掌握的并不是 Promise.all (即使这是一个很好用的工具);需要掌握的是思考在程序中,哪些部分应该并行运行,哪些不用。在本例中,甚至超时都可以在读取文件的时候并行运行:具体如何判断取决于你要解决的问题。如果说本例中重要的是读取三个文件完毕后,然后再等待60秒,最后把文件内容合并后并写入另一个文件,其实这些已经实现了。另一方面,也许希望程序在读取三个文件的同时异步等待60秒,在读取文件结束后或者60秒结束后,将结果写入第四个文件。这种情况下,可能就需要把超时挪到 Promise.all 中了。