在Node.js中,我需要读取一个文件并验证它的内容,所有内容都是异步的。我使用 Node.js 6.6 , bluebird 3.4.6
示例代码:
// pseudo function to read file contents - resolves when 'flag' is true, rejects when 'flag' is false.
function readFile(flag) {
return new Promise(function (resolve, reject) {
console.log('Reading file...');
if (flag) {
resolve('File contents');
} else {
reject('readFile error');
}
});
}
// pseudo function to validate file contents - resolves when 'flag' is true, rejects when 'flag' is false.
function validate(fileContents, flag) {
return new Promise(function (resolve, reject) {
console.log('Validating file: ', fileContents);
if (flag) {
resolve('Validate passed');
} else {
reject('validation failed');
}
});
}
readFile(false)
.then(function (fileContents) {
console.log('Successfully read the file:', fileContents);
return fileContents;
})
.catch(function (fileReadErr) {
console.log('Failed to read the file:', fileReadErr);
throw fileReadErr; // or, return Promise.reject(err);
})
.then(function (fileContents) {
return validate(fileContents, false);
})
.then(function (result) {
console.log('Successfully validated the file:', result);
})
.catch(function (err) {
console.log('Failed to validate the file:', err);
})
;

<script src="https://cdn.jsdelivr.net/bluebird/3.4.6/bluebird.min.js"></script>
&#13;
上面的代码将打印
Reading file...
Failed to read the file: readFile error
Failed to validate the file: readFile error
上述承诺链大致转换为以下同步代码:
try {
let fileContents;
try {
fileContents = readFile(false);
console.log('Successfully read the file:', fileContents);
} catch (e) {
console.log('Failed to read the file:', e);
throw e;
}
let validationResult = validate(fileContents, false);
console.log('Successfully validated the file:', validationResult);
} catch (err) {
console.log('Failed to validate the file:', err);
}
并且,在第一个catch
方法中投掷或拒绝仍然会调用第二个catch
方法。
我的问题:一旦文件读取失败,有没有办法打破链条?我的目标是从express.js路由返回不同的HTTP状态代码(文件读取错误:500,验证失败:400)。
我知道使用非标准专用catch
方法的解决方案,但这需要特殊处理。从某种意义上说,我需要在错误对象中抛出错误或需要一些过滤密钥,而这两者都不在我手中,并且需要一些工作来实现它。 bluebird docs&amp; amp;提到了这个解决方案。在这里:Handling multiple catches in promise chain
答案 0 :(得分:4)
到目前为止,最简单的解决方案是使用我称之为&#34;绝缘捕获&#34;。即,每个.catch()
是专家的模式,与整个过程中的特定步骤相关联,主链仅包括。(最终是单个,终端捕获)。
此外,在这种情况下,通过重新抛出具有附加属性的Error对象,可以在错误路径中传递添加的信息。这样可以避免出现自定义错误。
Promise.resolve()
.then(function() {
return readFile(false)
.then(function (fileContents) {
console.log('Successfully read the file:', fileContents);
return fileContents;
})
.catch(function (error) {
error.code = 521; // or whatever
error.customMessage = 'Failed to read the file';
throw error;
})
})
.then(function (fileContents) {
return validate(fileContents, false)
.then(function (result) {
console.log('Successfully validated the file:', result);
return fileContents;
})
.catch(function (error) {
error.code = 522; // or whatever
error.customMessage = 'Failed to validate the file';
throw error;
});
})
.catch(function(error) { // terminal catch.
console.log(error);
// It's possible for unaugmented errors to reach this point,
// so be sure to test for the extra properties before trying to use them.
if(error.code) {...}
if(error.customMessage) {...}
// Note also that the original error.message is still intact.
});
最初的Promise.resolve()
并非绝对必要,但有助于保持其他所有内容的对称性。
这适用于任何Promises / A + lib。不需要蓝鸟糖。
答案 1 :(得分:2)
您可以创建自定义错误类型,如下所示:
ReadFileError = function() {};
ReadFileError.prototype = Error.prototype;
ValidationError = function() {};
ValidationError.prototype = Error.prototype;
然后,你可以从承诺中throw
而不是拒绝:
function validate(fileContents, flag) {
return new Promise(function (resolve, reject) {
console.log('Validating file: ', fileContents);
if (flag) {
resolve('Validate passed');
} else {
throw new ReadFileError('readFile error');
}
});
}
然后,您可以根据其类型捕获不同的错误:
readFile(false)
.then(function (fileContents) {
console.log('Successfully read the file:', fileContents);
return fileContents;
})
.then(function (fileContents) {
return validate(fileContents, false);
})
.then(function (result) {
console.log('Successfully validated the file:', result);
})
.catch(ReadFileError, function (err) {
console.log(..., err);
})
.catch(ValidationError, function (err) {
console.log(..., err);
})
catch(function(err) {
...
});
答案 2 :(得分:1)
也许更多人可能会遇到同样的问题。我个人认为这不是最好的方法,因为那时你有你的应用程序抛出伪错误,可能会错误地由服务器上的其他错误处理处理。但它就像你提议的那样:
// pseudo function to read file contents - resolves when 'flag' is true, rejects when 'flag' is false.
function readFile(flag) {
return new Promise(function (resolve, reject) {
console.log('Reading file...');
if (flag) {
resolve('File contents');
} else {
throw new Error ('errorReading');
}
});
}
// pseudo function to validate file contents - resolves when 'flag' is true, rejects when 'flag' is false.
function validate(fileContents, flag) {
return new Promise(function (resolve, reject) {
console.log('Validating file: ', fileContents);
if (flag) {
resolve('Validate passed');
} else {
throw new Error ('validationFailed');
}
});
}
readFile(false)
.then(function (fileContents) {
console.log('Successfully read the file:', fileContents);
return fileContents;
})
.then(function (fileContents) {
return validate(fileContents, false);
})
.then(function (result) {
console.log('Successfully validated the file:', result);
})
.catch((error) => {
console.log(error.name);
console.log(error.message);
if (error.message === 'errorReading'){
console.log('error 500 - File could\'d be read');
// Maybe more custom error processing here
//return res.status(500).send(JSON.stringify({
// 'status' : 'error',
// 'message' : 'File could\'d be read'
//}));
} else if (error.message=== 'validationFailed'){
console.log('error 500 - Validation not OK');
// Maybe more custom error processing here
//return res.status(500).send(JSON.stringify({
// 'status' : 'error',
// 'message' : 'Validation not OK'
//}));
} else {
console.log('error 500 - Some really bad stuff!');
//return res.status(500).send(JSON.stringify({
// 'status' : 'error',
// 'message' : 'Some really bad stuff!',
// 'errorMessage': error
//}));
}
});
<script src="https://cdn.jsdelivr.net/bluebird/3.4.6/bluebird.min.js"></script>
请注意,我注释了res.send
快递,以避免处理此代码段时出错!
答案 3 :(得分:0)
据我了解你想要实现的目标,我建议总是使用一个单一的catch块(什么时候可以避免在promise逻辑中引入嵌套,这在几个用例中完全没问题,但是应该可以避免,因为你可能最终会承诺带有缩进的地狱)
您能否以统一的方式处理函数readFile
,validate
中的所有错误,如:
const error = new Error('something bad happened')
error.status = 500
return reject(error)
然后,您可以根据status
res.status(err.status || 500).json(...)
(例如onSaveInstanceState