我在所有Node.js项目中都使用了promise library Bluebird。为了从文件路径列表中获取第一个现有文件的内容,我成功使用Promise.any
,如下所示:
Promise.any([
'./foo/file1.yaml',
'./foo/file2.yaml',
'./foo/file3.yaml'
], function(filePath) {
_readFile(filePath);
}),then(function(fileContent) {
_console.log(fileContent);
});
我的问题是,如果在读取文件时遇到与“找不到文件”不同的错误,我怎么能提前离开Promis.any
循环?以下代码说明了我的问题:
Promise.any([
'./foo/file1.yaml',
'./foo/file2.yaml',
'./foo/file3.yaml'
], function(filePath) {
_readFile(filePath)
.catch(function(err) {
var res = err;
if (err.code == FILE_NOT_FOUND) {
// continue the Promise.any loop
} else {
// leave the Promise.any loop with this error
err = new Promise.EarlyBreak(err);
}
Promise.reject(err);
});
}).then(function(fileContent) {
_console.log(fileContent);
}, function(err) {
// the first error different from FILE_NOT_FOUND
});
可能Promise.any
不是正确的功能吗?
答案 0 :(得分:4)
提前离开Promise.any()
循环在概念上是有问题的,因为Promise.any()
是一个聚合器而不是循环,并接受一个承诺数组,每个承诺都有自己的生命,不是由{确定的{1}}。
但是,从一个路径数组开始,您寻找的循环可以表示为Promise.any()
表达式,它构建一个paths.reduce(...)
链,直接如下:
.catch()
Catch chain:credit Bergi
这样构建的.catch链将在失败时进入下一次迭代,或者在成功时跳到链的末尾。这种流量控制与更正常的.then链中发生的情况相反(以满足的承诺为种子)。
但那不是一切。需要一个额外的条件 - 即“如果我得到一个与'找不到文件'不同的错误,则提前离开[Promise.any]循环”。通过向成功路径发送除FILE_NOT_FOUND之外的所有错误,可以非常简单地将其设计到捕获链中,从而:
function getFirstGoodFileContent(paths) {
paths.reduce(function(promise, path) {
return promise.catch(function() {
return _readFile(path);
});
}, Promise.reject()); // seed the chain with a rejected promise.
}
所以你现在可以打电话:
function getFirstGoodFileContent(paths) {
paths.reduce(function(promise, path) {
return promise.catch(function() {
return _readFile(path).catch(function(err) {
if (err.code == FILE_NOT_FOUND) {
throw err; // Rethrow the error to continue down the catch chain, seeking a good path.
} else {
return { isError: true, message: err.code }; // Skip the rest of the catch chain by returning a "surrogate success object".
}
});
});
}, Promise.reject()).then(function(fileContent) {
// You will arrive here either because :
// * a good path was found, or
// * a non-FILE_NOT_FOUND error was encountered.
// The error condition is detectable by testing `fileContent.isError`
if (fileContent.isError) {
throw new Error(fileContent.message); // convert surrogate success to failure.
} else {
return fileContent; // Yay, genuine success.
}
});
}