首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >计算链中的其他操作符,而不是combineLatest,以避免冗余计算

计算链中的其他操作符,而不是combineLatest,以避免冗余计算
EN

Stack Overflow用户
提问于 2016-11-06 23:06:12
回答 2查看 360关注 0票数 2

我已经成功地使用RxJS将更大的Excel计算迁移到JS。任何输入数据都表示为可观察的,当任何Excel公式使用多个输入时,随后的计算将使用.map.combineLatest实现。

除了一个问题外,这个方法很好用。下面是一个简化的示例:

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

当$b现在被更新/释放一个新的输入值(例如4)时,$abbc会被计算两次--首先当$ab被更新时(导致错误的结果$abbc=10),再一次当$bc被更新时,导致正确的结果12

虽然最终结果是正确的,但中间计算是错误的和多余的。是否有任何方法只在$b被更新时执行最后一次计算,同时在a$c$被更新时仍然更新计算(这就排除了zip操作符)。我理解,这个示例显然可以简化为省略中间步骤,直接从$a$b$c中计算出$b,但在实际示例中,这是不可能的/不可行的。

下面是JSbin中运行的示例:https://jsbin.com/pipiyodixa/edit?js,console

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-11-07 08:38:59

这里的问题是RxJS的行为通过它的设计是正确的。

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

您想要的是处理“层”中的值。abc,然后是acbc,然后再计算最终值abbc

我能想到的唯一方法就是使用JavaScript执行上下文和使用setTimeout(() => {}, 0)的技巧。这样,您就不会安排任何超时(实际上是真正的> 0),而只是在JavaScript完成当前执行后在另一个执行上下文中运行闭包。

糟糕的是,为了避免多次重新释放值,您需要缓存更多的值(因为有merge()):

代码语言:javascript
运行
复制
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()技巧)。

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

另外,如果添加a$.next(5);,最后的计算只执行一次(这可能是好的,也可能是坏的:)。

我不知道这是否解决了您的问题,因为正如我所说的,RxJS是这样工作的。我还没有在任何更复杂的例子上测试过它,所以也许这不是您可以在最后使用的方法。

请注意,cache()操作符在RC.1中已被删除,目前还没有替换:https://github.com/ReactiveX/rxjs/blob/master/CHANGELOG.md

票数 2
EN

Stack Overflow用户

发布于 2016-11-08 22:48:02

基于@martin的(正确)答案,我创建了一个执行combineLatestDelayed的rxjs操作符:

代码语言:javascript
运行
复制
Rx.Observable.prototype.combineLatestDelayed = function(b$, cb) {
  var a2$ = this.cache(1);
  var b2$ = b$.cache(1);
  return a2$
    .merge(b2$)
    .auditTime(0)
    .withLatestFrom(a2$, b2$, (_, a, b) => cb(a,b));
}

这样,我只需要用.combineLatestDelayed替换原始的.combineLatestDelayed调用。

代码语言:javascript
运行
复制
var a$ = new Rx.BehaviorSubject(1).do(x => console.log("Emitting $a=" + x)); 
var b$ = new Rx.BehaviorSubject(2).do(x => console.log("Emitting $b=" + x)); var b1$ = b$.cache(1);
var c$ = new Rx.BehaviorSubject(3).do(x => console.log("Emitting $c=" + x));

var ab$ = a$
  .combineLatestDelayed(b1$, (a, b) => a + b)
  .do(x => console.log('ab$: $a + $b = ' + x))

var bc$ = b1$
  .combineLatestDelayed(c$, (b, c) => b + c)
  .do(x => console.log('bc$: $b + $c = ' + x))

var abbc$ = ab$
  .combineLatestDelayed(bc$, (ab, bc) => ab + bc)
  .do(x => console.log('$abbc: $ab + $bc = ' + x));

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

setTimeout(() => b$.next(4), 100);

完整JS Bin 这里

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40455579

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档