我开始习惯于承诺驱动代码,但我发现自己经常重复代码。特别是,我有一个Ionic应用程序,我在那里进行许多API调用,在运行调用之前,我检查是否存在Internet连接以及用户是否经过身份验证。这些功能中的每一个都是这样构建的:
noteCreate(): Promise<any> {
return new Promise (resolve => {
this.connCheck()
.then(success => {
if (success) {
this.authCheck('Please login first!')
.then(success => {
if (success) {
// API CALL
}
});
}
})
});
}
我希望有一种方法可以装饰我的API调用或将这两个检查浓缩成简单而不那么笨重/重复的东西,但我不确定我应该怎么做。
我查找connCheck
和authCheck
以返回true
以继续API调用。我确实希望将这些功能分开,因为在某些情况下,我只需要检查连接,而在其他情况下只需要进行身份验证(本地)。
connCheck(): Promise<boolean> {
return new Promise(resolve => {
this.http.get(this.myURL() + '/heartbeat/', {responseType: 'text'}).subscribe(
(data) => {
resolve(true);
},
(err) => {
resolve(false);
}
);
})
}
authCheck(message: string): Promise<boolean> {
return this.storage.get('user').then((data) => {
if (data) {
return true;
} else {
return false;
}
});
}
答案 0 :(得分:2)
此代码包含反模式,有时称为nested promisees反模式和promise构造反模式(deferred antipattern的近亲)。
已经有了可以链接的承诺。无需创建另一个new Promise (resolve => ...)
。
承诺需要有限的嵌套级别。所有的承诺都应该被束缚。如果承诺只是闲逛并且没有被退回,这是一个错误。
如果有多个条件,可以通过拒绝承诺链来实现平衡:
noteCreate(): Promise<any> {
const alreadyAuthorized = new Error();
return this.connCheck()
.then(success => {
if (success)
return this.authCheck('Please login first!')
else
throw alreadyAuthorized ;
})
.then(success => {
if (success) {
return ... // API CALL
}
))
.catch(err => {
if (err === alreadyAuthorized)
return;
else
throw err;
});
}
更方便的方法是切换到async..await
,因为它是为了提供承诺控制流而提供的语法糖。拒绝可以重写为从函数中提前返回:
async noteCreate(): Promise<any> {
if (!(await this.connCheck()))
return;
if (!(await this.authCheck('Please login first!')))
return;
return ... // API CALL
}
将this.http.get(...).subscribe(...)
与promises结合使用是一个错误。 Observable可以轻松转换为promises并返回:
connCheck(): Promise<boolean> {
return this.http.get(this.myURL() + '/heartbeat/', {responseType: 'text'})
.map(Boolean) // maps data to a boolean
.toPromise();
}
答案 1 :(得分:1)
承诺的全部意义在于能够将逻辑链接起来。如果链条的任何部分失败,您可以在最后捕获它。你可以这样做:
return this.connCheck()
.then(() => this.authCheck())
.then(() => {
... API call...
})
.catch(error => ...)
如果任何承诺被拒绝,将触发捕获。
你应该把捕获物放在你的承诺链的最后。