关于RxJS开篇是takeUntil
,主要源于最近刚修复了一个神奇的bug。遂以takeUntil
做为开篇。
看到bug
是不是瞬间就激动、兴奋了。下面且看引起这个bug的代码:
// ...
this.stream$
.pipe(
takeUntil(this.compelete$),
switchMap(id =>
combineLatest(
this.store.pipe(select(getAuth, { id, name: 'create' })),
this.store.pipe(select(getAuth, { id, name: 'edit' })),
this.service.getWhiteList()
)
),
)
.subscribe(([res1, res2, res3]) => {
// ...
});
// ...
上面这段代码,主体还是比较容易理解的,监听stream$
变化,获取 create
,edit
权限,以及白名单,然后 do something。这个时候 bug 就出现了,表象比较简单就是:白名单设置的权限有问题。
通过各种 debug,终于发现问题,正常使用时,断点会进入上述代码的subscribe
,可是其他异常情况依然进入了上述代码的subscribe
。
自我检查:takeUntil 写了,destroy 写了,destroy 里 this.complete$.complete()
也写了。
那么问题出在哪里了呢?
原来就出在了 takeUntil
这里,takeUntil
写在switchMap
前面,那么takeUntil
虽然结束了,但是switchMap
这个流依然没被关闭。于是乎,讲takeUntil
放在switchMap
后面,尝试之后问题确实解决了。
当
this.complete$
结束时,由takeUntil
操作符返回的 observable 就算完成了,其订阅也会被自动取消。
然而,由于stream$
的订阅者所订阅的 observable 并非由takeUntil
返回,而是由switchMap
返回,所以当takeUntil
的observable 完成时,stream$
的订阅是不会被自动取消的。
在switchMap
的所有 observable 全部完成之前,stream$
的订阅者都将始终保持订阅。所以,除非combineLatest
率先完成,否则这个订阅将不会结束
是不是所有的takeUntil
都应该放在最后呢?
当然并不是所有的takeUntil
都应该放在最后。
同时,项目上已经大量使用 rxjs,之前没有align过takeUntil
应该放哪,在项目全局搜索会发现这种潜在的bug还有很多,于是乎发现了 rxjs-lint-rules 其中rxjs-no-unsafe-takeuntil
,可以帮助检测出所有不规范的,然后逐一修复。
网友评论