当我有时希望它静默失败时处理 Promise 捕获错误的最佳方法
Best way to handle Promise catch errors when I sometimes want it to fail silently
我正在使用 Ionic 4 编写一个 Ionic 应用程序,我在让我的 Promise 以正确的顺序执行时遇到了一些问题(或者我可能只是在考虑这个错误)。这也是我第一次使用 Typescript,所以请多多包涵。
该应用程序需要与我们使用 Oauth 的 API 交互。我正在使用离子存储存储 Oauth 令牌,它也使用 Promises for get/set 所以这增加了我的问题。
如果您采用以下文件片段:
oauth.service.ts:
export class OauthService {
...
public async setTokens(token: string, token_secret: string) {
return Promise.all([this.storage.set('token', token), this.storage.set('token_secret', token_secret)]);
}
public async getTokens() {
return Promise.all([this.storage.get('token'), this.storage.get('token_secret')]);
}
...
}
api.service.ts:
export class ApiService {
...
public async getCustomer() {
const requestData = {
.. request data ..
};
return this.authorisedRequest(requestData);
}
private authorisedRequest(requestData) {
return this.oauth.getTokens().then(([token, token_secret]) => {
if (!token || !token_secret) {
return Promise.reject('Tokens not available');
}
const tokens = {
'key': token,
'secret': token_secret
};
const oauthHeader = this.oauth.createHeader(requestData, tokens);
const headers = this.createHeaders({
'Authorization': oauthHeader.Authorization
});
return this.apiRequest(requestData.method, requestData.url, {}, headers);
}).catch((error) => {
// @todo what to do here, if anything?
console.info('token error:', error)
});
}
private async apiRequest(type, path, data, headers = null) {
if (!headers) {
headers = this.headers;
}
const response = new Subject();
const httpRequest = new HttpRequest(
type,
path,
data,
{
headers: headers
}
);
this.http.request(httpRequest).subscribe((res: any) => {
if (res.type) {
response.next(res.body);
}
}, error => {
const responseError = error.error.messages.error[0];
this.alerter.presentAlert(responseError.message);
response.error(error);
});
return response;
}
}
authentication.service.ts:
export class AuthenticationService {
...
public checkAuth() {
this.api.getCustomer().then((request: Subject<any>) => {
// this still executes but request is undefined.
request.subscribe((resp: any) => {
this.isLoggedIn = true;
}, (error) => {
this.isLoggedIn = false;
});
});
}
...
}
在大多数情况下,这在令牌确实存在的所有情况下都是正常的,因为承诺没有被拒绝。
然而,当我 运行 checkAuth() 在初始化(检查用户是否已经登录)时,getTokens() 承诺 returns 立即被拒绝(在 api.service) 但 checkAuth 中的 'then' 仍然是 运行 即使它应该被捕获,这给了我一个错误:
TypeError: Cannot read property 'subscribe' of undefined
我可以将 catch 块移动到 checkAuth 函数内部,但这意味着我必须在我进行 API 调用(~30 个奇数端点)的所有情况下都这样做,这并不理想.
完全没有捕获我得到这个错误:
Uncaught (in promise): Tokens not available
我怎样才能让拒绝无声地失败,或者只是通过 checkAuth 传递错误?
还是我完全以错误的方式进行此过程?我确实觉得我检索 oauth 令牌的过程在这里是错误的(导致任何 api 调用的嵌套承诺)。
主要问题是您以错误的方式混合了 Observables
和 Promises
。
为简单起见,我建议一次只使用其中一个。
简单的解决方法:
checkAuth() {
this.api.getCustomer()
.then((request: Subject<any>) => request.toPromise())
.then(() => { this.isLoggedIn = true; })
.catch(() => { this.isLoggedIn = false; });
}
或
import { from } from 'rxjs';
checkAuth() {
const customersObservable = from(this.api.getCustomer());
customersObservable.subscribe(
() => { this.isLoggedIn = true; },
() => { this.isLoggedIn = false; }
);
}
更好的解决方案:
在较低级别使用 Promises 或 Observables 使您的服务 API 清晰。
示例:
export class OauthService {
public async getTokens(): Promise<any> { ... }
}
export class ApiService {
public async getCustomers(): Promise<Customer> {
...
return await this.authRequest(someRequest);
}
private async authorisedRequest(request) : Promise<any> {
const [token, token_secret] = await this.oauth.getTokens();
if (!token || !token_secret) {
throw 'Tokens not available';
}
return await this.apiRequest(request);
}
private async apiRequest(request) : Promise<any> {
const httpRequest = ...;
// Here we are converting our Observable to a Promise to avoid mixing
return await this.http.request(httpRequest)
.toPromise();
}
}
export class AuthenticationService {
public async checkAuth() {
try {
await this.api.getCustomer();
this.isLoggedIn = true;
} catch {
this.isLoggedIn = false;
}
}
}
您也可以通过 使用 Observable
的方法(一般代码将类似于带有承诺的示例,所以我跳过它)
我正在使用 Ionic 4 编写一个 Ionic 应用程序,我在让我的 Promise 以正确的顺序执行时遇到了一些问题(或者我可能只是在考虑这个错误)。这也是我第一次使用 Typescript,所以请多多包涵。
该应用程序需要与我们使用 Oauth 的 API 交互。我正在使用离子存储存储 Oauth 令牌,它也使用 Promises for get/set 所以这增加了我的问题。
如果您采用以下文件片段:
oauth.service.ts:
export class OauthService {
...
public async setTokens(token: string, token_secret: string) {
return Promise.all([this.storage.set('token', token), this.storage.set('token_secret', token_secret)]);
}
public async getTokens() {
return Promise.all([this.storage.get('token'), this.storage.get('token_secret')]);
}
...
}
api.service.ts:
export class ApiService {
...
public async getCustomer() {
const requestData = {
.. request data ..
};
return this.authorisedRequest(requestData);
}
private authorisedRequest(requestData) {
return this.oauth.getTokens().then(([token, token_secret]) => {
if (!token || !token_secret) {
return Promise.reject('Tokens not available');
}
const tokens = {
'key': token,
'secret': token_secret
};
const oauthHeader = this.oauth.createHeader(requestData, tokens);
const headers = this.createHeaders({
'Authorization': oauthHeader.Authorization
});
return this.apiRequest(requestData.method, requestData.url, {}, headers);
}).catch((error) => {
// @todo what to do here, if anything?
console.info('token error:', error)
});
}
private async apiRequest(type, path, data, headers = null) {
if (!headers) {
headers = this.headers;
}
const response = new Subject();
const httpRequest = new HttpRequest(
type,
path,
data,
{
headers: headers
}
);
this.http.request(httpRequest).subscribe((res: any) => {
if (res.type) {
response.next(res.body);
}
}, error => {
const responseError = error.error.messages.error[0];
this.alerter.presentAlert(responseError.message);
response.error(error);
});
return response;
}
}
authentication.service.ts:
export class AuthenticationService {
...
public checkAuth() {
this.api.getCustomer().then((request: Subject<any>) => {
// this still executes but request is undefined.
request.subscribe((resp: any) => {
this.isLoggedIn = true;
}, (error) => {
this.isLoggedIn = false;
});
});
}
...
}
在大多数情况下,这在令牌确实存在的所有情况下都是正常的,因为承诺没有被拒绝。
然而,当我 运行 checkAuth() 在初始化(检查用户是否已经登录)时,getTokens() 承诺 returns 立即被拒绝(在 api.service) 但 checkAuth 中的 'then' 仍然是 运行 即使它应该被捕获,这给了我一个错误:
TypeError: Cannot read property 'subscribe' of undefined
我可以将 catch 块移动到 checkAuth 函数内部,但这意味着我必须在我进行 API 调用(~30 个奇数端点)的所有情况下都这样做,这并不理想.
完全没有捕获我得到这个错误:
Uncaught (in promise): Tokens not available
我怎样才能让拒绝无声地失败,或者只是通过 checkAuth 传递错误?
还是我完全以错误的方式进行此过程?我确实觉得我检索 oauth 令牌的过程在这里是错误的(导致任何 api 调用的嵌套承诺)。
主要问题是您以错误的方式混合了 Observables
和 Promises
。
为简单起见,我建议一次只使用其中一个。
简单的解决方法:
checkAuth() {
this.api.getCustomer()
.then((request: Subject<any>) => request.toPromise())
.then(() => { this.isLoggedIn = true; })
.catch(() => { this.isLoggedIn = false; });
}
或
import { from } from 'rxjs';
checkAuth() {
const customersObservable = from(this.api.getCustomer());
customersObservable.subscribe(
() => { this.isLoggedIn = true; },
() => { this.isLoggedIn = false; }
);
}
更好的解决方案:
在较低级别使用 Promises 或 Observables 使您的服务 API 清晰。
示例
export class OauthService {
public async getTokens(): Promise<any> { ... }
}
export class ApiService {
public async getCustomers(): Promise<Customer> {
...
return await this.authRequest(someRequest);
}
private async authorisedRequest(request) : Promise<any> {
const [token, token_secret] = await this.oauth.getTokens();
if (!token || !token_secret) {
throw 'Tokens not available';
}
return await this.apiRequest(request);
}
private async apiRequest(request) : Promise<any> {
const httpRequest = ...;
// Here we are converting our Observable to a Promise to avoid mixing
return await this.http.request(httpRequest)
.toPromise();
}
}
export class AuthenticationService {
public async checkAuth() {
try {
await this.api.getCustomer();
this.isLoggedIn = true;
} catch {
this.isLoggedIn = false;
}
}
}
您也可以通过 Observable
的方法(一般代码将类似于带有承诺的示例,所以我跳过它)