RXJS 仅在以前的值不是那么好并且我真的需要一个更好的值时才订阅
RXJS subscribe only if previous value is not that great and I really need a better one
我有一个昂贵的服务器 ajax 请求,它有一个输入 (full: boolean
)。如果 full
是 false
,服务器可以 return 部分或完整响应 (response.isFull == true
);但是如果 full
是 true
,服务器 将 return 一个完整的响应。通常部分响应就足够了,但在某些情况下需要完整响应。我需要尽可能避免明确请求完整响应,所以我想我会从一个 BehaviorSubject
开始,我最终可以用 true
提供它,如果我可以将它与 distinctUntilChanged
结合起来永远需要得到完整的回应。这将给我一个带有 false
的可观察对象,如果我将其输入它可以给我 true
:
const fullSubject = new BehaviorSubject<boolean>(false);
然后我得到一个函数,它接受一个布尔参数和 return 一个可观察到的服务器请求(重试、转换等)。如前所述,答案可以是部分的或完整的,但即使服务器判断输入参数为假,答案也可以是完整的。例如:
interface IdentityData {
...
isFull: boolean;
}
private getSimpleIdentity(full: boolean): Observable<IdentityData> {
return Axios.get(`/api/identity${full?"?full=true":""}`)
.pipe( ... retry logic ...,
... transformation logic ...,
shareReplay(1) );
}
我需要知道如何将它们结合起来才能满足以下条件:
- 服务器最多需要查询两次。
- 如果第一个答案是完整答案,则无需向服务器执行进一步查询。
- 如果第一个答案是部分答案,并且
true
被输入 fullSubject
,则必须请求完整答案。
所有这一切的预期输出是一个可观察的,它发出一个完整响应或一个部分响应,并在被询问时发出一个完整响应。
环境:Vue 2.6.11、RxJS 6.5.5、Axios 0.19.2、TypeScript 3.7.5。
提前致谢
如果我没记错的话
private getSimpleIdentity(): Observable<IdentityData> {
return fullSubject.pipe(
switchMap(full => Axios.get(`/api/identity${full ? "?full=true" : ""}`)),
shareReplay(1),
);
}
使用 retryWhen() 运算符
const source = of("").pipe(map(() => Math.floor(Math.random() * 10 + 1)));
const example = source
.pipe(
tap((val) => console.log("tap", val)),
map((val) => {
//error will be picked up by retryWhen
if (val !== 5) throw val;
return val;
}),
retryWhen((errors) =>
errors.pipe(
tap(() => console.log("--Wait 1 seconds then repeat")),
delay(1000)
)
)
)
.subscribe((val) => console.log("subscription", val));
/*
output:
tap 3
--Wait 1 seconds then repeat
tap 8
--Wait 1 seconds then repeat
tap 1
--Wait 1 seconds then repeat
tap 4
--Wait 1 seconds then repeat
tap 7
--Wait 1 seconds then repeat
tap 5
subscription 5
*/
这是我的方法:
const fullSubject = new BehaviorSubject(false);
const src$ = fullSubject.pipe(
switchMap(isFull => Axios.get('...')),
take(2), // Server required at most twice
takeWhile(response => !response.isFull, true), // When `isFull`, it will complete & unsubscribe -> no more requests to the server
shareReplay(1),
);
src$.subscribe(() => { /* ... */ });
function getFullAnswer () {
fullSubject.next(true);
}
takeWhile
取 second argument、inclusive
。当设置为 true 时,当谓词函数的计算结果为 false(例如 isFull 为 true)时,它也会发送该值。 –
我有一个昂贵的服务器 ajax 请求,它有一个输入 (full: boolean
)。如果 full
是 false
,服务器可以 return 部分或完整响应 (response.isFull == true
);但是如果 full
是 true
,服务器 将 return 一个完整的响应。通常部分响应就足够了,但在某些情况下需要完整响应。我需要尽可能避免明确请求完整响应,所以我想我会从一个 BehaviorSubject
开始,我最终可以用 true
提供它,如果我可以将它与 distinctUntilChanged
结合起来永远需要得到完整的回应。这将给我一个带有 false
的可观察对象,如果我将其输入它可以给我 true
:
const fullSubject = new BehaviorSubject<boolean>(false);
然后我得到一个函数,它接受一个布尔参数和 return 一个可观察到的服务器请求(重试、转换等)。如前所述,答案可以是部分的或完整的,但即使服务器判断输入参数为假,答案也可以是完整的。例如:
interface IdentityData {
...
isFull: boolean;
}
private getSimpleIdentity(full: boolean): Observable<IdentityData> {
return Axios.get(`/api/identity${full?"?full=true":""}`)
.pipe( ... retry logic ...,
... transformation logic ...,
shareReplay(1) );
}
我需要知道如何将它们结合起来才能满足以下条件:
- 服务器最多需要查询两次。
- 如果第一个答案是完整答案,则无需向服务器执行进一步查询。
- 如果第一个答案是部分答案,并且
true
被输入fullSubject
,则必须请求完整答案。
所有这一切的预期输出是一个可观察的,它发出一个完整响应或一个部分响应,并在被询问时发出一个完整响应。
环境:Vue 2.6.11、RxJS 6.5.5、Axios 0.19.2、TypeScript 3.7.5。
提前致谢
如果我没记错的话
private getSimpleIdentity(): Observable<IdentityData> {
return fullSubject.pipe(
switchMap(full => Axios.get(`/api/identity${full ? "?full=true" : ""}`)),
shareReplay(1),
);
}
使用 retryWhen() 运算符
const source = of("").pipe(map(() => Math.floor(Math.random() * 10 + 1)));
const example = source
.pipe(
tap((val) => console.log("tap", val)),
map((val) => {
//error will be picked up by retryWhen
if (val !== 5) throw val;
return val;
}),
retryWhen((errors) =>
errors.pipe(
tap(() => console.log("--Wait 1 seconds then repeat")),
delay(1000)
)
)
)
.subscribe((val) => console.log("subscription", val));
/*
output:
tap 3
--Wait 1 seconds then repeat
tap 8
--Wait 1 seconds then repeat
tap 1
--Wait 1 seconds then repeat
tap 4
--Wait 1 seconds then repeat
tap 7
--Wait 1 seconds then repeat
tap 5
subscription 5
*/
这是我的方法:
const fullSubject = new BehaviorSubject(false);
const src$ = fullSubject.pipe(
switchMap(isFull => Axios.get('...')),
take(2), // Server required at most twice
takeWhile(response => !response.isFull, true), // When `isFull`, it will complete & unsubscribe -> no more requests to the server
shareReplay(1),
);
src$.subscribe(() => { /* ... */ });
function getFullAnswer () {
fullSubject.next(true);
}
takeWhile
取 second argument、inclusive
。当设置为 true 时,当谓词函数的计算结果为 false(例如 isFull 为 true)时,它也会发送该值。 –