并发活动的语言同步('map-reduce')在节点中?

编辑

感谢答复,我有一个工作版本。 问题结束时的代码; 感谢@estus和@Jared的帮助。

原来的问题

我的方式进入节点,并试图获得并发处理。 从一个简单的例子开始:给定两个文件的名字,确定哪个更大。 常规(顺序)解决scheme:

var fs = require('fs'); var fname1=process.argv[2] var fname2=process.argv[3] var stats1 = fs.statSync(fname1) size1=stats1["size"] var stats2 = fs.statSync(fname2) size2=stats2["size"] if(size1 > size2) { console.log(fname1 + " is bigger") } else if (size2 > size1) { console.log(fname2 + " is bigger") } else { console.log("The files are the same size") } 

现在假设我想并行统计文件*。 我可以将代码转换为使用asynchronousstatfunction:

 var fs = require('fs'); var fname1=process.argv[2] var fname2=process.argv[3] fs.stat(fname1, function doneReading(err, stats) { size1=stats["size"] fs.stat(fname2, function doneReading(err, stats) { size2=stats["size"] if(size1 > size2) { console.log(fname1 + " is bigger") } else if (size2 > size1) { console.log(fname2 + " is bigger") } else { console.log("The files are the same size") } }) }) 

然而:

  1. 它的可读性较差;
  2. 如果我想比较> 2个文件,它将不能很好地扩展;
  3. 不知道它甚至会并行统计文件(我不清楚如何后台线程工作)。

所以,具体来说,以下的惯用方法是:

  1. 然后同时产生多个操作
  2. 一旦完成,使用他们的综合结果?

也许承诺可能是一个候选人? Promise.all看起来像等待所有承诺的方式,但不清楚如何实际使用他们的结果。

谢谢。

 'use strict'; const co = require('co'); const fs = require('fs-promise'); var fname1=process.argv[2] var fname2=process.argv[3] co(function* () { let res = yield [fs.stat(fname1), fs.stat(fname2)]; let size1 = res[0]["size"] let size2 = res[1]["size"] if(size1 > size2) { console.log(fname1 + " is bigger") } else if (size2 > size1) { console.log(fname2 + " is bigger") } else { console.log("The files are the same size") } }) 

它非常可读,简洁,完全没有callback的麻烦。 并可以随时扩展比较n个文件。

*是的,我知道这种情况下不需要这样做。 目的是用一个简单的例子来理解模式。

 fs.stat(fname1, function doneReading(err, stats) { ... fs.stat(fname2, function doneReading(err, stats) { ... 

仍然是顺序的而不是并行的,与fs.statSync的区别在于它的fs.stat是非阻塞的。

现代节点中build议的“可读”方法是promise和cofs.stat可能被promisified(与pify或蓝鸟的Promise.promisify / Promise.promisifyAll )。 或者可以使用一些现有的promisified fs包,如fs-promise

以上代码的顺序和非阻塞替代可能如下所示:

 'use strict'; const co = require('co'); const fs = require('fs-promise'); co(function* () { let stat1 = yield fs.stat(fname1); let stat2 = yield fs.stat(fname2); ... }); 

如果我们想使它平行, Promise.all步骤如下:

 co(function* () { let [stat1, stat2] = yield [fs.stat(fname1), fs.stat(fname2)]; // a shortcut for // let [stat1, stat2] = yield Promise.all([fs.stat(fname1), fs.stat(fname2)]); ... }); 

除了estus的出色答案之外,这可能更容易些:

 let stat = Promise.promisify(fs.stat.bind(fs)); Promise.all(arrOfPaths.map(stat)).then(arrOfResults => { // do stuff }); 

如上所述,您需要编写promisify函数或使用添加它的库。

这是一个示例实现:

 const promisify = fn => { return function(...args) { return new Promise((resolve, reject) => { fn.apply(this, [...args, (err, ...rest) => { if (err) { reject(err); } let result; switch (rest.length) { case 0: result = true; break; case 1: result = rest[0]; break; default: result = rest; break; } resolve(result); }]); }); }; };