像这样的任何类型的复杂逻辑确实会从对每个异步操作使用 Promise 中受益,尤其是当您处理错误时,而且也只是用于构建逻辑流。
由于您没有提供任何实际代码,我将制作一个示例。假设您有两个都返回承诺的核心异步操作:query(...) 和 store(...)。
然后,您可以像这样实现上述逻辑:
query(...).then(function(value) {
if (value === X) {
return store(value).then(function() {
return query(...).then(function(newValue) {
if (newValue === Y) {
return store("something");
} else {
return store("something else");
}
})
});
} else {
return store("that").then(function() {
return store("the other thing");
});
}
}).then(function() {
// everything succeeded here
}, function(err) {
// error occurred in anyone of the async operations
});
我不会假装这很简单。七种不同异步操作之间实现的逻辑流程无论你怎么做都只是一些代码。但是,Promise 可以减少痛苦,并且大大简化了强大的错误处理工作并将其与其他异步操作接口。
这里使用的 Promise 的主要键是:
- 让所有异步操作返回以值解析或以失败为原因拒绝的承诺。
- 然后,您可以将
.then() 处理程序附加到任何 Promise 以查看异步操作何时成功完成或出现错误。
-
.then() 的第一个回调是成功处理程序,第二个回调是错误处理程序。
- 如果您从
.then() 处理程序中返回一个promise,则该promise 将“链接”到前一个promise,因此所有成功和错误状态都将链接并返回到原始promise 状态。这就是为什么你会看到上面的代码总是返回嵌套的 Promise。这会自动将错误一直返回给调用者,并允许您将值一直返回给调用者,即使来自深度嵌套的 Promise。
- 如果上述代码中的任何 Promise 被拒绝,那么它将停止该 Promise 链,直到找到实际的拒绝处理程序并将该错误传播回该拒绝处理程序。由于上述代码中唯一的拒绝处理程序位于 to 级别,因此无论嵌套异步混乱发生多深,都可以在此处捕获和查看所有错误(尝试使用普通回调可靠地做到这一点 - 这非常困难)。
原生承诺
Node.js 现在内置了 Promise,因此您可以为此使用本机 Promise。但是,node.js 实现的 Promise 规范并不是特别丰富,所以很多人使用 Promise 库(我使用 Bluebird 进行所有 node.js 开发)来获得额外的功能。更突出的功能之一是能够“承诺”现有的非承诺 API。这允许您获取一个仅适用于回调的函数,并创建一个通过 Promise 工作的新函数。我发现这特别有用,因为许多已经存在一段时间的 API 本身并不返回 Promise。
承诺一个非承诺接口
假设您有一个使用传统回调的异步操作,并且您想“承诺”它。这是一个如何手动执行此操作的示例。假设你有db.query(whatToSearchFor, callback)。您可以像这样手动承诺它:
function queryAsync(whatToSearchFor) {
return new Promise(function(resolve, reject) {
db.query(whatToSearchFor, function(err, data) {
if (!err) {
reject(err);
} else {
resolve(data);
}
});
});
}
然后,您只需调用 queryAsync(whatToSearchFor) 并使用返回的承诺。
queryAsync("foo").then(function(data) {
// data here
}, function(err) {
// error here
});
或者,如果您使用 Bluebird promise library 之类的东西,它有一个函数用于承诺任何异步函数,该函数通过作为最后一个参数传递的 node.js 样式回调来传达其结果:
var queryAsync = Promise.promisify(db.query, db);