我使用 RxJS 事件流和 fetch API 来发出两个连续的 HTTP 请求,其中第一个请求的结果必须传递到第二个请求。我已经很接近了,但是,合并两个流是有问题的:
const xhrUrlBase = "http://localhost:4556/api";
const xhrButton = document.querySelector("#xhr-rxjs");
const xhrTriggerClickStream = fromEvent(xhrButton, "click");
const xhr$ = of(xhrUrlBase).pipe(
concatMap(url => {
return fromFetch(`${xhrUrlBase}/a`).pipe(
switchMap(response => response.json())
);
}),
concatMap(fromFirstCall => {
return fromFetch(`${xhrUrlBase}/b?fromA=${fromFirstCall.toB}`).pipe(
switchMap(response => response.json()),
map(fromSecondCall => ({
fromFirstCall,
fromSecondCall
}))
);
})
);
/* option A */
const clickAndXhr$ = xhrTriggerClickStream
.pipe(
flatMap(() => xhr$)
)
/* option B */
const clickAndXhr$ = combineLatest(
xhrTriggerClickStream,
xhr$
)
clickAndXhr$.subscribe(([, returnedDataFromBothHttpRequests]) => {
console.log({ returnedDataFromBothHttpRequests }); // got data from both responses
});
选项 [A] 有效,但每次单击按钮时都会发出请求(我仍然不完全确定我在这里正确使用了 flatMap
)。我想要 combineLatest
的功能,我可以像选项 [B] 一样从两者中获取最新的流。但是,该选项不会等待单击,并且 HTTP 请求是在页面加载时发出的。我需要的是介于两者之间的东西。
此练习中出现了几个问题:
1) 如何组合这些流,以便在单击按钮时发出一次 HTTP 请求,然后在后续的按钮单击时仅返回初始响应?
2) 设置代码(第 4 - 20 行)非常冗长且嵌套。有没有更惯用的方法来做到这一点。在我上面有 switchMap
的地方,flatMap
也可以工作(返回一个值),而 map
会给我(在最终订阅中)一个决心的 promise 。控制台显示 [[PromsieStatus]]: "resolved"
和 [[PromiseValue]]:/* the right object */
,但是我真的不明白怎么回事就像 rxjs switchMap 具有解开 promise 的能力一样。为什么这两个运算符都以这种方式工作?
3) 将 concatMap
更改为 flatMap
也不会改变功能。当出现如此多的重叠时,我如何知道哪个是合适的运算符?
最佳答案
您可以使用选项 a
并在 xhr$
流末尾添加 shareReplay
运算符。
const xhr$ = of(xhrUrlBase).pipe(
concatMap(url => {
return fromFetch(`${xhrUrlBase}/a`).pipe(
switchMap(response => response.json())
);
}),
concatMap(fromFirstCall => {
return fromFetch(`${xhrUrlBase}/b?fromA=${fromFirstCall.toB}`).pipe(
switchMap(response => response.json()),
map(fromSecondCall => ({
fromFirstCall,
fromSecondCall
}))
);
})
shareReplay(1),
);
关于javascript - 为顺序提取选择适当的运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59346293/