Javascript 节点中并发活动的惯用同步(';map reduce';)?

Javascript 节点中并发活动的惯用同步(';map reduce';)?,javascript,node.js,ecmascript-6,es6-promise,Javascript,Node.js,Ecmascript 6,Es6 Promise,编辑 多亏了答案,我有了一个有效的版本。问题末尾的代码;感谢@estus和@Jared的帮助 原始问题 以我的方式进入节点,并试图获得并发的句柄。从一个简单的例子开始:给定两个文件的名称,确定哪个文件更大。常规(顺序)解决方案: var fs = require('fs'); var fname1=process.argv[2] var fname2=process.argv[3] var stats1 = fs.statSync(fname1) size1=stats1["size"]

编辑

多亏了答案,我有了一个有效的版本。问题末尾的代码;感谢@estus和@Jared的帮助

原始问题

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

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")
}
现在假设我想并行统计这些文件*。我可以将代码转换为使用async
stat
函数:

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")
        }
    })
})
然而:

  • 它的可读性较差
  • 如果我想比较>2个文件,它的伸缩性就不好
  • 甚至不确定它会并行地统计文件(我不清楚后台线程是如何工作的)
  • 那么,具体来说,什么是惯用方式:

  • 并发生成多个操作,然后
  • 一旦全部完成,是否使用它们的组合结果
  • 也许承诺可能是候选人<代码>承诺。所有看起来像是等待所有承诺的方式,但不清楚如何实际使用它们的结果

    谢谢

    解决方案

    '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")
        }
    })
    
    它可读性强,简洁,而且完全没有污点。并且易于扩展到比较n个文件

    --

    *是的,我知道在这种情况下没有必要这样做;目的是通过一个简单的例子来理解模式

    fs.stat(fname1, function doneReading(err, stats) {
        ...
        fs.stat(fname2, function doneReading(err, stats) {
        ...
    
    仍然是顺序的而不是并行的,与fs.statSync的区别在于它是非阻塞的

    现代节点中建议的“可读”方法是promises和
    co
    fs.stat
    可以是promisified(使用
    pify
    或蓝鸟的
    promisify.promisify
    /
    promisify.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);
        ...
    });
    
    如果我们想让它并行,
    承诺。所有
    步骤如下:

    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)]);
        ...
    });
    
    仍然是顺序的而不是并行的,与fs.statSync的区别在于它是非阻塞的

    现代节点中建议的“可读”方法是promises和
    co
    fs.stat
    可以是promisified(使用
    pify
    或蓝鸟的
    promisify.promisify
    /
    promisify.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);
        ...
    });
    
    如果我们想让它并行,
    承诺。所有
    步骤如下:

    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);
          }]);
        });
      };
    };
    

    除了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);
          }]);
        });
      };
    };