来自AngularJS,我正在努力解决下一个问题。我需要一个返回对象的函数(让我们称之为a,但在该函数中包含的所有请求都得到解决之前,无法返回该对象
- 对象A是从远程服务器下载的
- 使用A,我们对另一个对象(B(执行操作
- B从服务器下载
- B使用A中的一些属性进行修补
- 使用A和B的结果,我们对第三个对象执行操作,C
- C从服务器下载
- C使用A和B中的一些属性进行修补
- 处理B和C后,函数必须返回A
我想了解如何使用rxjs来做这样的事情,但对于Angular 6,互联网上的大多数示例似乎都不推荐使用,而且教程对我没有真正的帮助。我无法修改后端以使其更优雅。非常感谢。
考虑以下可观测值:
const sourceA = httpClient.get(/*...*/);
const sourceB = httpClient.get(/*...*/);
const sourceC = httpClient.get(/*...*/);
其中httpClient
是Angular的HTTPClient。
您描述的操作顺序如下:
const A = sourceA.pipe(
switchMap(a => sourceB.pipe(
map(b => {
// do some operation using a and b.
// Return both a and b in an array, but you can
// also return them in an object if you wish.
return [a,b];
})
)),
switchMap(ab => sourceC.pipe(
map(c => {
// do some operations using a, b, and/or c.
return a;
})
))
);
现在您只需要订阅A
:
A.subscribe(a => console.log(a));
您可以在此处阅读有关RxJs运算符的信息。
首先,在我看来,正如所描述的,这个函数调用将以某种方式阻止调用过程,直到所有指定的事件都发生为止——这在JavaScript中当然是不合理的。
因此,首先,我认为您的函数应该需要一个回调,作为它可能唯一的参数,当一切最终发生时,该回调将被调用。
现在,关于"如何优雅地处理步骤1、2和3">。。。立刻想到的是有限状态机(FSM(算法的概念。
假设您的函数调用会导致一个新的"请求"被放置在某个请求表队列上,如果需要,还会导致一个定时器请求(设置为在1毫秒内关闭(为该队列提供服务。(除其他外,该条目将包含对回调的引用。(我们还假设请求被赋予一个随机字符串"nonce",该字符串将用于唯一标识它:它将被传递给各种外部请求,并且必须包含在它们相应的回复中。
FSM的思想是,请求将具有状态(属性(,例如:DOWNLOADING_FROM_B
、B_DOWNLOADS_COMPLETE
、DOWNLOADING_FROM_C
、C_REQUESTS_COMPLETE
等。这样,将在这个完全异步过程中发挥作用的每个回调都将(1(能够通过其nonce来定位请求条目,然后(2(明确地"知道下一步该做什么",以及"分配什么新状态(如果有(",仅基于对条目的state
的检查。
例如,当状态达到C_REQUESTS_COMPLETE
时,应该调用您最初提供的回调,并删除请求表条目。
你可以很容易地绘制出在任意复杂的场景中可能发生的所有"状态转换"(什么状态可以导致什么状态,以及当它们发生时该做什么(,无论你是否真的创建了一个数据结构来表示所谓的"状态表",尽管有时你这样做会更优雅(!(
当然,这是一种经典的算法,适用于"太阳下的每一种编程语言"。(许多硬件设备也使用它。(