我如何链接多个承诺?

我不太清楚,也许我错过了一些显而易见的事情,但我无法弄清楚如何链接两个承诺。

我的基于callback的代码看起来像这样:

async.series([ function (cb) { // Create the directory if the nodir switch isn't on if (!nodir) { fs.mkdir('somedirectory', function (err) { if (err) { log('error while trying to create the directory:\n\t %s', err) process.exit(0) } log('successfully created directory at %s/somedirectory', process.cwd()) cb(null) }) } cb(null) }, function (cb) { // Get the contents of the sample YML fs.readFile(path.dirname(__dirname) + '/util/sample_config.yml', function (err, c) { var sampleContent = c if (err) { log('error while reading the sample file:\n\t %s', err) process.exit(0) } log('pulled sample content...') // Write the config file fs.writeFile('db/config.yml', sampleContent, function (err) { if (err) { log('error writing config file:\n\t %s', err) process.exit(0) } log('successfully wrote file to %s/db/config.yml', process.cwd()) cb(null) }) }) } ]) 

我已经开始尝试重构这个基于承诺的stream程,这是我迄今为止:

 if (!nodir) { fs.mkdirAsync('somedirectory').then(function () { log('successfully created directory at %s/somedirectory', process.cwd()) }).then(function () { // how can I put fs.readFileAsync here? where does it fit? }).catch(function (err) { log('error while trying to create the directory:\n\t %s', err) process.exit(0) }) } 

(我使用蓝鸟,所以我之前做了Promise.promisifyAll(fs)

问题是,我不知道在哪里放置前一个系列的第二个“步骤”。 我把它放在那里还是在它的function? 我是否将它归还并放在一个单独的函数中?

任何帮助将不胜感激。

通常,promise驱动的代码如下所示:

 operation.then(function(result) { return nextOperation(); }).then(function(nextResult) { return finalOperation(); }).then(function(finalResult) { }) 

在你的例子中有很多,但总的想法是这样的:

 Promise.resolve().then(function() { if (nodir) { return fs.mkdir('somedirectory').catch(function(err) { log('error while trying to create the directory:\n\t %s', err); process.exit(0); }); } }).then(function() { return fs.readFile(path.dirname(__dirname) + '/util/sample_config.yml').catch(function(err) { log('error while reading the sample file:\n\t %s', err); process.exit(0); }) }).then(function(sampleContent) { log('pulled sample content...'); return fs.writeFile('db/config.yml', sampleContent).catch(function(err) { log('error writing config file:\n\t %s', err) process.exit(0) }) }).then(function() { log('successfully wrote file to %s/db/config.yml', process.cwd()) }) 

这假设你使用的所有电话都是原生的。

最初的Promise.resolve()只是一个开始链条的承诺,因为你的第一步是有条件的。

既然你使用的是蓝鸟,你可以使用大量的糖,比接受的答案IMO有更多的更清洁的代码:

 var fs = Promise.promisifyAll(fs); // tell bluebird to work with FS Promise.try(function(){ if(nodir) return fs.mkdirAsync('somedirectory'). catch(catchErr("Could not create dir")); }).then(function(){ return fs.readFileAsync(path.dirname(__dirname) + '/util/sample_config.yml'). catch(catchErr("error while reading the sample file")); }).then(function(data){ log('pulled sample content...'); return fs.writeFile('db/config.yml', data). catch(catchErr("error writing config file")); }).then(function(){ log('successfully wrote file to %s/db/config.yml', process.cwd()) }, function(err){ // centralized error handling, to remove the redundancy log(err.message); log(err.internal); log(err.stack); // this is important! }); function catchErr(msg){ // helper to rethrow with a specific message return function(e){ var err = new Error(msg); err.internal = e; // wrap the error; throw e; }; } 

我会进一步去,并会删除你在这里有更细粒度的错误,因为你使用的types真的不提供这些API方法提供的内置消息的附加信息 – 缩短您的代码:

 Promise.try(function(){ if(nodir) return fs.mkdirAsync("somedirectory"); }).then(function(){ fs.readFileAync(path.dirname(__dirname) + '/util/sample_config.yml'); }).then(function(data){ log('pulled sample content...'); return fs.writeFile('db/config.yml', data); }).then(function(){ log('successfully wrote file to %s/db/config.yml', process.cwd()) }).catch(function(err){ log(err); process.exit(1); }); 

承诺是安全的,并提供理智和合格的error handling – 相当不错的胜利,如果你问我。 如果你使用io.js或者现代节点,你可以使用:

 Promise.coroutine(function*(){ // generators ftw if(nodir) yield fs.mkdirAsync("somedirectory"); var data = yield fs.readFileAsync(path.dirname(__dirname) + '/util/sample_config.yml'); log("pulled sample content"); yield fs.writeFileAsync("db/config.yml", data); log('successfully wrote file to %s/db/config.yml', process.cwd()); })(); process.on("unhandledRejection", function(p, r){ throw r; // quit process on promise failing });