javascript - 处理 AJAX 请求时使用 Observables 的原因
问题描述
我已经开始使用响应式扩展 (RxJS),并且我了解当数据及时分布(或数据流)时使用 Observables 的强大功能。前 - 观察 mouseDown 事件等。但我很难在 API 调用的上下文中理解它们的用例
当我进行 API 调用时,我有一个服务器会返回 5 个名称。这是一个常规的 GET 请求,它在一个响应中返回所有 5 个名称。为什么我应该为此使用可观察的而不是 Promise?我不太了解使用 Observables 进行 API 调用。
感谢帮助,谢谢。
解决方案
Observables 是 Promise 的超集。
如果你可以用 来做Promise
,那么你可以用 来做Observable
。您可能会坚持使用的一个原因Promises
是Observable
JavaScript 中没有内置的语法糖(异步等待)。
不建议将两者混合使用。没有性能或互操作性问题,但如果你无论如何都要使用 RxJS Observables,那么尽可能地坚持使用 Observables 是最清楚的(可维护性、可扩展性、可调试性)。
为什么要使用 Observables?
程序通常会随着时间的推移执行任务。您可以通过将数据视为一段时间内的流来抽象出一定级别的回调。
代替
async function userButtonPress(event){
const response = await apiCall(event.thingy);
/* More code */
}
你得到
userButtonPresses$.pipe(
mergeMap(event => apiCall(event.thingy))
).subscribe(response => {
/* More code */
});
这是否更好?嗯,是的,这意味着您正在将按钮按下作为数据流而不是回调函数。好处是多种多样的。
每个按钮单击都会启动另一个并发 api 调用
如果没有以某种方式管理,这就是事件回调中的 api 调用的行为。
userButtonPresses$.pipe(
mergeMap(event => apiCall(event.thingy))
).subscribe(response => {
/* More code */
});
每个按钮单击都会排队另一个 api 调用,该调用在前一个完成之前不会开始
如果您想Promise
等待轮到它,您将需要一个库或数据结构,让您的函数知道何时可以免费启动。
userButtonPresses$.pipe(
concatMap(event => apiCall(event.thingy))
).subscribe(response => {
/* More code */
});
每次单击按钮都会取消正在进行的 api 调用(如果有的话)并开始一个新的
Promises
没有本地方法来取消正在进行的进程,因此您需要一个库来扩展 Promise 并提供一些额外的功能。这是您管理并发 Promise 所需的一项。
userButtonPresses$.pipe(
switchMap(event => apiCall(event.thingy))
).subscribe(response => {
/* More code */
});
到目前为止,按下了多少次按钮?
userButtonPresses$.pipe(
switchMap((event, index) => apiCall(event.thingy).pipe(
map(response => ({response, index}))
))
).subscribe(({response, index}) => {
console.log(`This is response #${index}: `, response);
/* More code */
});
如果它们之间的距离超过一秒,则忽略按钮按下
使用 Promise,您可以设置一个变量(范围在您的回调函数之外),const time = Date.now()
并查看在开始您的 api 调用之前是否已经过了 1 秒。使用 RxJS,它是一个简单的运算符。
我们仍然会计算我们忽略的按钮按下,但我们会忽略靠得太近的按钮按下。
userButtonPresses$.pipe(
map((event, index) => ({event, index})),
throttleTime(1000),
switchMap(({event, index}) => apiCall(event.thingy).pipe(
map(response => ({response, index}))
))
).subscribe(({response, index}) => {
console.log(`This is response #${index}: `, response);
/* More code */
});
按下按钮开始每 500 毫秒轮询一次 API 端点
我们仍然会计算按钮按下,并限制它们(因为为什么不呢?)。
userButtonPresses$.pipe(
map((event, index) => ({event, index})),
throttleTime(1000),
switchMap(({event, index}) => timer(0, 500).pipe(
concatMap(_ => apiCall(event.thingy).pipe(
map(response => ({response, index}))
))
)
).subscribe(({response, index}) => {
console.log(`This is response #${index}: `, response);
/* More code */
});
承诺示例
在这里,您将需要变量来手动处理所有内容。它更难测试,并且不能保证其他一些过程不会弄乱这些变量。如果在调用完成之前单击下一个按钮,即使像取消先前的 api 调用这样简单的操作也不适用于本机承诺。
这是您如何计算按钮按下的方法
let buttonPresses = 0;
async function userButtonPress(event){
// There's no saying how often the global buttonPresses will be incremended while
// we await this promise, so we need a local copy that doesn't change.
const inScopeButtonPresses = buttonPresses++;
const response = await apiCall(event.thingy);
console.log(`This is response #${inScopeButtonPresses}: `, response);
/* More code */
}
推荐阅读
- button - 文件名作为 PowerBI 中的度量
- mongodb - 用猫鼬更新文档——一个属性没有被更新?
- android - 将 apk 集成到 AOSP 的构建系统中并在启动时运行它
- python - TensorFlow py_function 设置返回值形状
- mysql - 更新并选择具有非唯一标识符的 FIFO 队列中的 MySQL 表
- r - Shiny App 未使用 dplyr 和 %in% 运算符进行过滤
- blockchain - Chainlink 消费者合约中回调地址的用途是什么?
- google-analytics - 无法在 Google Analytics(分析)中配置目标
- javascript - React 钩子形式 - 对话框内的字段数组(材料 UI)
- r - Rollapply 或类似的时间序列数据中的多条件阈值