带承诺的多路流的正确模式
Correct pattern for multiway flows with Promises
所以我一直在玩承诺在过去的几天里,只是试图转换一些项目,使用承诺,但不止几次我遇到了这个问题。
在阅读文章和教程时,一切看起来都很流畅和干净:
getDataFromDB()
.then(makeCalculatons)
.then(getDataFromDB)
.then(serveToClient)
但现实并非如此。
程序有很多if条件,这些条件改变了整个流程:
getDataFromCache(data).then(function(result){
if(result){
return result;
}else{
return getDataFromDB();
}
}).then(function(result){
if(result){
serveToClient() //this does not return a promise, so undefined returned...
}else{
return getDataFromWebService(); //this does return a promise,
}
}).then(function(result){
//i dont want to reach here if i already serveToClient()...
//so i basically have to check "if(result)" for all next thens
if(result){
//do more stuff
}
}).then(...
我有两个主要问题:
- 我发现自己在
then
回调上添加了很多if
条件。 - 我仍然进入下一个
then
回调,即使我已经完成(serveToClient
)
我是否遵循了正确的模式?
您无法避免if
语句,因为这是逻辑流所必需的。如果你不想在if
的一个部分继续承诺链,你将不得不分支你的控制流。因此,如果在第二个.then()
处理程序的某些部分,您不想继续到第三个.then()
处理程序,那么您需要像这样分支逻辑,并将后续的.then()
处理程序放入第二个.then()
处理程序中,在它们自己的逻辑分支中。
你不能只是继续顶级分支,因为在主链中中止未来.then()
逻辑的唯一方法是拒绝承诺(你可能不想这样做)或在每个.then()
处理程序中添加另一个if
检查来决定是否应该跳过它(恶心)。
所以,你可以这样划分逻辑:
getDataFromCache().then(function(result){
if(!result) {
return getDataFromDB()
} else {
return result;
}
}).then(function(result){
// branch promise chain here into two separate branches
if(result){
// do not continue the promise chain here
// call a synchronous operation
serveToClient();
} else {
// continue promise chain here
return getDataFromWebService().then(function(result) {
if(result){
//do more stuff
}
}).then(...); // you can continue the promise chain here
}
}).catch(function(err) {
// process any errors here
});
你可能会发现这些答案很有用:
理解javascript承诺;栈和链接
promise.then.then和promise.then有区别吗?promise.then
供参考,你可以重新组织上面的代码,使其更简洁一点,像这样:
getDataFromCache().then(function(result) {
if (result)
serveToClient();
} else {
return getDataFromWebService().then(function(result) {
if(result){
//do more stuff
}
}).then(...); // you can continue the promise chain here
}
}).catch(function(err) {
// process any errors here
});
另一个答案解释了分支,但你也要求"平滑和干净"。
你可以使用ES6的箭头函数:
getDataFromCache()
.then(result => result || getDataFromDB())
.then(result => result ? serveToClient() : getDataFromWebService()
.then(result => { /* Won't reach here if serveToClient */ }))
.then(() => { /* can continue promise chain here */ })
.catch(e => console.log(e));
请注意缩进的.then
在getDataFromWebService()
上,并在尾部看到两个))
。这很好地反映了同步分支。
您可以使用ES8 async
/await
(现在可以在Chrome Canary和Firefox Nightly中使用!):
try {
if (await getDataFromCache() || await getDataFromDB()) {
serveToClient();
} else {
let result = await getDataFromWebService();
/* Won't reach here if serveToClient */
}
/* can continue here */
} catch (e) {
// process any errors here
}
后者提供了完全的控制,就好像事情是同步的一样,只要它在async
函数中。
- 用于多个选项卡和模块化的knockoutjs设计模式
- 多次调用方法后返回相同promise的模式
- 如何在JQuery全日历周模式中选择多天
- (阅读更多链接)到模式淡入淡出视图
- 如何在同一页面上的多个按钮上打开一个引导模式
- 如何在变量中存储多个模式参数并在 JavaScript 中打印该变量的值
- 包含 2 个或更多对象的页面上的 JavaScript 设计模式
- 设置多个观察程序以触发动态事件的角度替代解决方案 - 优化的观察者模式
- 如何验证多个模式
- Safari限制?使用多种方法来显示多个自定义模式对话框
- 一个页面中有多个引导模式
- Twtitter Bootstrap模式显示事件多次触发
- 多个引导模式的滚动问题
- 将多个值传递到引导模式窗体
- JS:两个或多个非严格模式下具有相同名称的对象属性
- 使用非阻塞算法多次显示模式窗口
- alert/Confirm使用fullCalendar eventClick在bootsrap模式上多次触发
- 如何从科尔多瓦发出多路请求
- 带承诺的多路流的正确模式
- 使用javascript/jQuery实现多路切换的最佳方式是什么?