NodeJS - 使用 Promise 对文件流进行哈希处理

Sir*_*ert 1 file stream node.js promise es6-promise

我现在有一个统计和哈希(可能很大)文件的流程。现在我正在这样做:

function gen_hash (fn, callback) {
  var hash = crypto.createHash('sha256');

  var fh = fs.createReadStream(fn);
  fh.on('data', d => hash.update(d));
  fh.on('end', () => {
    var digest = hash.digest('hex');
  });
}

function gen_stat (fn, callback) {
  fs.stat(fn, function (err, stats) {
    if (err) {
      if (err.code == "ENOENT") {
        file.exists = false;
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后我有一些代码允许在它们都完成时进行回调。正如你可以想象的那样,它相当……复杂。

我认为这与 Promise 非常匹配,但我不知道如何使用它们。

我尝试了一些类似的东西:

const Promises = require('bluebird');
const fs = Promises.promisifyAll(require('fs'));

fh = fs.createReadStream(fn)
.then...
.error...
Run Code Online (Sandbox Code Playgroud)

但我实际上不明白这里要做什么,而且蓝鸟网站似乎缺乏细节。

我觉得类似的东西Promise.all可能是正确的,但我只是没有看到任何正确语法的好例子。

我知道我可以编写一个包装函数,在各种条件下返回一个承诺,但我不太明白它在承诺领域是如何工作的。也许是这样的?

const fs = Promise.promisifyAll(require('fs'));

function promise_checksum (fn) {
  return new Promise((fulfill, reject) => {
  // What goes here...?
  }
}

function promise_stat (fn) {
  return new Promise((fulfill, reject) => {
    fs.stat(fn).then((err, stats) => {
      if (err) {
        reject(err);
      } else {
        fulfill(stats);
      }
    }
  }
}

function checksum_and_stat (fn) {
  return new PromiseAll((fulfill, reject) => {
    // What goes here?
  });
}
Run Code Online (Sandbox Code Playgroud)

帮助?

jfr*_*d00 6

您可以将您的函数包装在一个 Promise 中,如下所示:

function gen_hash (fn) {
    return new Promise((resolve, reject) => {
        var hash = crypto.createHash('sha256');
        var fh = fs.createReadStream(fn);

        fh.on('data', d => hash.update(d));
        fh.on('end', () => {
            var digest = hash.digest('hex');
            resolve(digest);
        });
        fh.on('error', reject);
    });
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

gen_hash(someFileName).then(hash => {
    console.log("hash is: ", hash);
}).catch(err => {
     console.err(err);
});
Run Code Online (Sandbox Code Playgroud)

对于node.jsfs模块中的常规函数​​,您可以使用Bluebird来promisify它们。

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));
Run Code Online (Sandbox Code Playgroud)

这将在以 Async 结尾的对象上创建新方法fs(除了作为标准fs模块一部分的常规方法之外),并且这些新方法将返回一个承诺,而不是接受回调。Bluebird 将调整这些方法中的每一个,并提供它自己的回调来为您管理承诺。这是一个例子:

fs.statAsync(someFileName).then(stats => {
    console.log(stats);
}).catch(err => {
     console.err(err);
});
Run Code Online (Sandbox Code Playgroud)

Promise.all()当您有多个单独的承诺并且您想知道它们何时全部履行时使用。它接受一组 Promise 作为参数,并返回一个新的主 Promise,该主 Promise 将使用一组值进行解析,或者在出现第一个错误时拒绝。所以,你可以这样做:

function checksum_and_stat (fn) {
    return Promise.all([gen_hash(fn), fs.statAsync(fn)]);
}

checksum_and_stat(someFileName).then(args => {
    console.log("hash: ", args[0]);
    console.log("stats: ", args[1]);
}).catch(err => {
    console.err(err);
});
Run Code Online (Sandbox Code Playgroud)