rxjs6:RetryWhen 返回计时器时不起作用
rxjs6: RetryWhen not work when returning timer
我正在构建一个小函数,它将在特定时间后刷新访问令牌(基于计算)。
public buildRefreshTokenTimerAsync(): Observable<LoginResultViewModel> {
let accessToken = '';
let refreshToken = '';
let lastRefreshTokenTime: number;
let issuedTokenTime: number;
let accessTokenLifeTime = ACCESS_TOKEN_LIFE_TIME;
let user: ProfileViewModel;
let retriedTime = 0;
// Load the last time the application refresh the access token.
const loadLastRefreshTokenTimeObservable = this.storageMap
.get<number>(LocalStorageKeyConstant.lastRefreshTokenAt)
.pipe(
tap((time: number) => {
lastRefreshTokenTime = time;
})
);
// Load login result from storage map observable.
const loadLoginResultObservable = this.storageMap
.get<LoginResultViewModel>(LocalStorageKeyConstant.loginResult)
.pipe(
tap((loginResult: LoginResultViewModel) => {
if (!loginResult || !loginResult.accessToken || !loginResult.accessToken.trim()) {
throw new Error(ExceptionCodeConstant.accessTokenNotFound);
}
if (!loginResult.refreshToken || !loginResult.refreshToken.trim()) {
throw new Error(ExceptionCodeConstant.refreshTokenNotFound);
}
accessToken = loginResult.accessToken;
refreshToken = loginResult.refreshToken;
issuedTokenTime = loginResult.issuedAt;
accessTokenLifeTime = loginResult.lifeTime;
user = loginResult.user;
})
);
return of(null)
.pipe(
flatMap(_ => {
return forkJoin([
loadLastRefreshTokenTimeObservable,
loadLoginResultObservable]);
}),
flatMap(() => {
// Get the current time in the system.
const currentTime = new Date().getTime();
// Calculate the time to refresh the access token.
const timeToRefreshToken = this.calculateAccessTokenRefreshTime(issuedTokenTime, ACCESS_TOKEN_LIFE_TIME);
// Access token hasn't been refreshed before.
if (lastRefreshTokenTime === undefined || lastRefreshTokenTime === null) {
// Refresh time was in the past. Refresh the token now.
if (currentTime >= timeToRefreshToken) {
return timer(0);
}
}
// Access token has refreshed before, however, another thread is handling the operation.
// Retry after the specific time.
if (currentTime - lastRefreshTokenTime < REFRESH_TIME_GAP) {
throw new Error(ExceptionCodeConstant.accessTokenIsRefreshing);
}
// Refresh time is in the future.
if (currentTime < timeToRefreshToken) {
const delayTime = timeToRefreshToken - currentTime;
return timer(delayTime);
}
return timer(0);
}),
flatMap(_ => this.loadRefreshTokenAsync(refreshToken)),
flatMap((loginResult: LoginResultViewModel) => {
loginResult.user = user;
return this.storageMap
.set(LocalStorageKeyConstant.loginResult, loginResult)
.pipe(
flatMap(_ => {
return this.storageMap.set(LocalStorageKeyConstant.lastRefreshTokenAt, new Date().getTime());
}),
map(() => {
return loginResult;
})
);
}),
retryWhen(errors => {
return errors
.pipe(
flatMap(error => {
retriedTime++;
if (retriedTime > 2) {
throw error;
}
if (!(error instanceof Error)) {
return throwError(error);
}
if (ExceptionCodeConstant.accessTokenIsRefreshing === (error as Error).message) {
return timer(2000);
}
return throwError(error);
})
);
})
);
}
我期望的是当抛出 ACCESS_TOKEN_IS_REFRESHING
异常时,该函数将在 2 秒后重试。
如果我用retry
代替retryWhen
,功能还可以,但是当我改成retryWhen
和return一个timer
,功能2 秒后不重试。
我做错了什么吗?
第一个:
I'm building a small function
发布一个带有主要缩进的 +100 行函数 :D
第二个:
我认为你不应该使用 flatMap
而应该使用 delayWhen
:
retryWhen((errors) => errors.pipe(
delayWhen((error) => {
retriedTime++;
if (retriedTime > 2) {
throw error;
}
if (!(error instanceof Error)) {
return throwError(error);
}
if (ExceptionCodeConstant.accessTokenIsRefreshing === (error as Error).message) {
return timer(2000);
}
return throwError(error);
})
))
简化 stackblitz 显示有效
我正在构建一个小函数,它将在特定时间后刷新访问令牌(基于计算)。
public buildRefreshTokenTimerAsync(): Observable<LoginResultViewModel> {
let accessToken = '';
let refreshToken = '';
let lastRefreshTokenTime: number;
let issuedTokenTime: number;
let accessTokenLifeTime = ACCESS_TOKEN_LIFE_TIME;
let user: ProfileViewModel;
let retriedTime = 0;
// Load the last time the application refresh the access token.
const loadLastRefreshTokenTimeObservable = this.storageMap
.get<number>(LocalStorageKeyConstant.lastRefreshTokenAt)
.pipe(
tap((time: number) => {
lastRefreshTokenTime = time;
})
);
// Load login result from storage map observable.
const loadLoginResultObservable = this.storageMap
.get<LoginResultViewModel>(LocalStorageKeyConstant.loginResult)
.pipe(
tap((loginResult: LoginResultViewModel) => {
if (!loginResult || !loginResult.accessToken || !loginResult.accessToken.trim()) {
throw new Error(ExceptionCodeConstant.accessTokenNotFound);
}
if (!loginResult.refreshToken || !loginResult.refreshToken.trim()) {
throw new Error(ExceptionCodeConstant.refreshTokenNotFound);
}
accessToken = loginResult.accessToken;
refreshToken = loginResult.refreshToken;
issuedTokenTime = loginResult.issuedAt;
accessTokenLifeTime = loginResult.lifeTime;
user = loginResult.user;
})
);
return of(null)
.pipe(
flatMap(_ => {
return forkJoin([
loadLastRefreshTokenTimeObservable,
loadLoginResultObservable]);
}),
flatMap(() => {
// Get the current time in the system.
const currentTime = new Date().getTime();
// Calculate the time to refresh the access token.
const timeToRefreshToken = this.calculateAccessTokenRefreshTime(issuedTokenTime, ACCESS_TOKEN_LIFE_TIME);
// Access token hasn't been refreshed before.
if (lastRefreshTokenTime === undefined || lastRefreshTokenTime === null) {
// Refresh time was in the past. Refresh the token now.
if (currentTime >= timeToRefreshToken) {
return timer(0);
}
}
// Access token has refreshed before, however, another thread is handling the operation.
// Retry after the specific time.
if (currentTime - lastRefreshTokenTime < REFRESH_TIME_GAP) {
throw new Error(ExceptionCodeConstant.accessTokenIsRefreshing);
}
// Refresh time is in the future.
if (currentTime < timeToRefreshToken) {
const delayTime = timeToRefreshToken - currentTime;
return timer(delayTime);
}
return timer(0);
}),
flatMap(_ => this.loadRefreshTokenAsync(refreshToken)),
flatMap((loginResult: LoginResultViewModel) => {
loginResult.user = user;
return this.storageMap
.set(LocalStorageKeyConstant.loginResult, loginResult)
.pipe(
flatMap(_ => {
return this.storageMap.set(LocalStorageKeyConstant.lastRefreshTokenAt, new Date().getTime());
}),
map(() => {
return loginResult;
})
);
}),
retryWhen(errors => {
return errors
.pipe(
flatMap(error => {
retriedTime++;
if (retriedTime > 2) {
throw error;
}
if (!(error instanceof Error)) {
return throwError(error);
}
if (ExceptionCodeConstant.accessTokenIsRefreshing === (error as Error).message) {
return timer(2000);
}
return throwError(error);
})
);
})
);
}
我期望的是当抛出 ACCESS_TOKEN_IS_REFRESHING
异常时,该函数将在 2 秒后重试。
如果我用retry
代替retryWhen
,功能还可以,但是当我改成retryWhen
和return一个timer
,功能2 秒后不重试。
我做错了什么吗?
第一个:
I'm building a small function
发布一个带有主要缩进的 +100 行函数 :D
第二个:
我认为你不应该使用 flatMap
而应该使用 delayWhen
:
retryWhen((errors) => errors.pipe(
delayWhen((error) => {
retriedTime++;
if (retriedTime > 2) {
throw error;
}
if (!(error instanceof Error)) {
return throwError(error);
}
if (ExceptionCodeConstant.accessTokenIsRefreshing === (error as Error).message) {
return timer(2000);
}
return throwError(error);
})
))
简化 stackblitz 显示有效