2016-12-18 59 views
0

我已经有一个过程,即统计和哈希(可能很大)的文件。现在我这样做:NodeJS - 使用承诺哈希文件流

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

然后我有一些代码,当他们都完成时允许回调。正如你可以想象的那样,这很公平......参与。

我认为这是Promises的一个很好的匹配,但我不知道如何使用它们。

我尝试了一些东西,如:

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

fh = fs.createReadStream(fn) 
.then... 
.error... 

但我不真正了解这里做什么,和蓝鸟网站似乎缺乏细节。

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

我明白我可以编写一个封装函数,它可以在各种条件下返回一个promise,但我并不完全知道它是如何在promise-land中起作用的。也许这样?

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

帮助?

回答

1

你可以用你的功能在这样一个承诺:

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

用法示例:

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

对于常规功能Node.js的fs模块,你可以使用蓝鸟以促成它们。

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

这将创建fs对象上的带有Async端(除了常规的那些是标准fs模块的一部分)和新方法,而不是接受的回调,这些新的方法将返回一个诺言。 Bluebird将会提供这些方法中的每一种,并提供自己的回调来管理您的承诺。这里有一个例子:

fs.statAsync(someFileName).then(stats => { 
    console.log(stats); 
}).catch(err => { 
    console.err(err); 
}); 

Promise.all()当你有多个独立的承诺,你想知道什么时候它们都满足使用。它接受一组承诺,因为它是参数,它返回一个新的主承诺,该承诺将用出现的第一个错误的值或拒绝数组来解决。所以,你可以这样做:

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); 
}); 
+0

太棒了,谢谢。这将很多松散的目标联系在一起,并帮助承诺'点击'到位。 –

+0

你可能想在这里小心。 hash.update被阻塞并且会阻塞事件循环。我可能会使用https://github.com/ronomon/crypto-async包来不这样做。 – JTWebMan

+0

@JTWebMan - 请将您的评论引导至OP,因为加密的选择是他们的。 – jfriend00