我有一个用于验证字符串的方法,我希望该方法返回一个承诺,因为正在运行的验证可能是异步的。然而,我遇到的问题是性能问题,我希望在可能的情况下在相同的事件循环中解决Promission(例如:当没有异步验证要做时),但我希望接口保持一致(例如:始终返回Promission)。
下面的简化代码示例说明了我正在尝试的操作,但是它会导致前面提到的性能损失,因为即使可以同步执行验证,它仍然等待下一个事件循环来处理结果。
在我的特定用例中,这种性能损失太高了。
下面是我正在做的一个简化的(最小的)示例
// Array containing validation methods
const validations = [
(value) => true, // Some validation would happen here
];
// Array containing asynchronous validation methods
const asyncValidations = []; // No async validations (but there could be)
const validate(value){
// Run synchronous validations
try {
validations.forEach(validation => validation(value));
catch(error){
// Synchronous validation failed
return Promise.reject();
}
if(asyncValidations){
return Promise.all(asyncValidations.map(validation => validation(value));
}
// Otherwise return a resolved promise (to provide a consistent interface)
return Promise.resolve(); // Synchronous validation passed
}
// Example call
validate('test').then(() => {
// Always asynchronously called
});
你提到了两件不同的事情:
>
我希望接口保持一致
[我想]永远回报一个承诺
如果您希望避免异步行为(如果不需要的话),您可以这样做并保持API的一致性。但是你不能做的是“总是返回一个承诺”,因为不可能“同步解决一个承诺”。
您的代码当前返回一个承诺,该承诺在不需要异步验证时被解析:
// Otherwise return a resolved promise (to provide a consistent interface) return Promise.resolve(); // Synchronous validation passed
您可以用以下代码替换该代码:
return {then: cb => cb()};
注意,这只是返回一个“thenable”的对象文字(即它有一个
then
方法),并将同步执行您传递给它的任何回调。但是,它并不回报一个承诺。您还可以通过实现
then
方法和/或catch
方法的可选onrejected
参数来扩展这种方法。
承诺异步解析的原因是它们不会炸毁堆栈。考虑以下使用承诺的堆栈安全代码。
null
console.time("promises");
let promise = Promise.resolve(0);
for (let i = 0; i < 1e7; i++) promise = promise.then(x => x + 1);
promise.then(x => {
console.log(x);
console.timeEnd("promises");
});