我如何链接多个承诺?
How do I chain multiple promises?
我不太确定,也许我遗漏了一些明显的东西,但我不知道如何链接两个承诺。
我基于回调的代码如下所示:
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)
})
})
}
])
我已经开始尝试将其重构为基于承诺的流程,这是我目前所拥有的:
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)
})
}
(我用的是Bluebird,所以我之前用过Promise.promisifyAll(fs)
)
问题是,我不知道把上一个系列的第二个 "step" 放在哪里。我是把它放在 then
中还是在它的函数中?我是否 return 它并将其放在一个单独的函数中?
如有任何帮助,我们将不胜感激。
通常 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 native。
最初的 Promise.resolve()
只是以承诺开始链条的东西,因为您的第一步是有条件的。
由于您使用的是 Bluebird,因此您可以使用大量糖分,并且代码比 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;
};
}
虽然我会更进一步,并且会删除您在此处遇到的更细粒度的错误,因为您使用的类型实际上没有提供比这些 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);
});
Promises 是安全的,并提供理智和认证的错误处理 - 如果你问我的话,这是相当不错的胜利。不过它会变得更好,如果你在 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
});
我不太确定,也许我遗漏了一些明显的东西,但我不知道如何链接两个承诺。
我基于回调的代码如下所示:
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)
})
})
}
])
我已经开始尝试将其重构为基于承诺的流程,这是我目前所拥有的:
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)
})
}
(我用的是Bluebird,所以我之前用过Promise.promisifyAll(fs)
)
问题是,我不知道把上一个系列的第二个 "step" 放在哪里。我是把它放在 then
中还是在它的函数中?我是否 return 它并将其放在一个单独的函数中?
如有任何帮助,我们将不胜感激。
通常 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 native。
最初的 Promise.resolve()
只是以承诺开始链条的东西,因为您的第一步是有条件的。
由于您使用的是 Bluebird,因此您可以使用大量糖分,并且代码比 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;
};
}
虽然我会更进一步,并且会删除您在此处遇到的更细粒度的错误,因为您使用的类型实际上没有提供比这些 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);
});
Promises 是安全的,并提供理智和认证的错误处理 - 如果你问我的话,这是相当不错的胜利。不过它会变得更好,如果你在 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
});