计算链中的其他运算符(而不是CombineLatest)可以避免冗余计算 [英] Other operator in calculation chain than combineLatest to avoid redundant calculations

查看:145
本文介绍了计算链中的其他运算符(而不是CombineLatest)可以避免冗余计算的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经成功地使用RxJS将较大的Excel计算迁移到JS.当任何Excel公式使用多个输入时,任何输入数据均表示为Observable,随后的计算将使用.map.combineLatest进行.

I've successfully migrated a larger Excel calculation to JS using RxJS. Any input data is represented as an Observable and subsequent calculations are implemented with .map and .combineLatest when any Excel formula uses more than one input.

除一个问题外,此方法效果很好.这是一个简化的示例:

This works great except for one problem. Here is a simplified example:

在两个不同的计算中使用三个输入(a$=1b$=2c$=3)(第一个是$ab = $a+$b = 3,第二个是$bc = $b+$c = 5)作为中间步骤来计算最终结果$abbc = $ab + $bc = 8 .

Three inputs (a$=1, b$=2, c$=3) are used in two different calculations ($ab = $a+$b = 3 in the first, $bc = $b+$c = 5 in the second) as intermediate steps to calculate the final result $abbc = $ab + $bc = 8.

当$ b现在被更新/发出新的输入值时(例如4),$ abbc被计算两次-首先是$ ab被更新(导致错误的结果$abbc=10),然后是$ bc更新,得到正确的结果12.

When $b is now updated/emitting a new input value (e.g. 4), $abbc is calculated twice - first when $ab is updated (resulting in the wrong result $abbc=10) and again when $bc is updated, resulting in the correct result 12.

虽然最终结果是正确的,但中间计算既错误又多余.有什么方法只能在$b被更新的情况下执行最后的计算-同时在a$c$被更新时仍会更新计算(这将排除zip运算符).我知道显然可以简化此示例,以省去中间步骤,并直接从$a$b$c计算$abbc-但在实际示例中,这是不可能/可行的.

While the final result is correct, the intermediate calculation is both wrong and redundant. Is there any way to only execute the last calculation in case $b gets updated - while still also updating the calculation when a$ or c$ is updated (which would rule out the zip operator). I understand that this example can obviously be simplified to leave out the intermediate steps and calculated $abbc directly from $a, $b and $c - but in the real live example this is not possible/feasible.

这是JSbin中正在运行的示例: https://jsbin.com/pipiyodixa/edit? js,控制台

Here's the running example in JSbin: https://jsbin.com/pipiyodixa/edit?js,console

推荐答案

此处的问题是RxJS的行为通过其设计是正确的.

The problem here is that RxJS's behavior is correct by its design.

确实应该先更新b => ab => abbc,然后再更新bc => abbc.它处理流中的值.

It really should first update b => ab => abbc and then bc => abbc. It processed values in streams.

您想要的是处理图层"中的值.abc,然后是acbc,然后计算最终值abbc.

What you want is to process values in "layers".a, b, c, then ac , bc and after that calculate final value abbc.

我能想到的唯一方法是利用JavaScript执行上下文和setTimeout(() => {}, 0)的技巧.这样,您就不会安排任何超时(实际上,真正的

The only way I can think of is to make use of JavaScript execution context and a trick with setTimeout(() => {}, 0). This way you don't schedule any timeout (in fact the real timeout might be > 0) and just run the closure in another execution context after JavaScript finishes executing the current one.

不好的是,要避免多次重发值,您甚至需要缓存更多(由于merge()):

The bad thing is that to avoid re-emitting values multiple times you need to cache even more (because of merge()):

var b2$ = b$.cache(1);

var ab$ = a$
  .combineLatest(b2$, (a, b) => a + b)
  .do(x => console.log('$a + $b = ' + x))
  .cache(1);

var bc$ = b2$
  .combineLatest(c$, (b, c) => b + c)
  .do(x => console.log('$b + $c = ' + x))
  .cache(1);

var abbc$ = new Rx.Observable.merge(ab$, bc$)
  .auditTime(0)
  .withLatestFrom(ab$, bc$, (_, ab, bc) => ab + bc)
  .do(x => console.log('$ab + $bc = ' + x));

console.log("Initial subscription:")
abbc$.subscribe();

b$.next(4);

auditTime() 运算符是这里最重要的事情.它会触发withLatestFrom()来更新其值,而当ab$bc$首次触发它时,它将忽略所有连续的发射,直到此关闭执行结束(这是setTimeout()技巧).

The auditTime() operator is the most important thing here. It triggers withLatestFrom() to update it's value while when it's triggered for first time by ab$ or bc$ it ignores all consecutive emits until the end of this closure execution (that's the setTimeout() trick).

观看现场演示: https://jsbin.com/zoferid/edit?js,console

此外,如果添加a$.next(5);,则最终计算仅执行一次(可能是好是坏:)).

Also, if you add a$.next(5); the final calculation is executed just once (which might be both good or bad :)).

我不知道这是否可以解决您的问题,因为正如我所说的RxJS可以这样工作.我还没有在任何更复杂的示例上进行过测试,因此也许这不是您最终可以使用的方式.

I don't know if this solves your problem because as I said RxJS works this way. I haven't tested it on any more complicated example so maybe this is not the way you can use at the end.

请注意,cache()运算符已在RC.1中删除,目前没有替代:

Note that cache() operator was removed in RC.1 and there's no replacement for now: https://github.com/ReactiveX/rxjs/blob/master/CHANGELOG.md

这篇关于计算链中的其他运算符(而不是CombineLatest)可以避免冗余计算的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆