Rxjs redux observable:一旦另一个动作至少触发一次,就立即映射到该动作
我有一个SPA,它正在从服务器加载一些全局/共享数据(让我们称这个应用程序为“加载”确定)和页面特定数据(仪表板“加载”确定)。我想显示一个加载动画,直到APP_LOAD_OK和DASHBOARD_LOAD_OK都被调度 现在我在用RxJS表达这一点时遇到了一个问题。我需要的是在每个仪表板加载正常后触发一个操作,只要至少有一个应用加载正常。大概是这样的:Rxjs redux observable:一旦另一个动作至少触发一次,就立即映射到该动作,rxjs,redux-observable,Rxjs,Redux Observable,我有一个SPA,它正在从服务器加载一些全局/共享数据(让我们称这个应用程序为“加载”确定)和页面特定数据(仪表板“加载”确定)。我想显示一个加载动画,直到APP_LOAD_OK和DASHBOARD_LOAD_OK都被调度 现在我在用RxJS表达这一点时遇到了一个问题。我需要的是在每个仪表板加载正常后触发一个操作,只要至少有一个应用加载正常。大概是这样的: action$ .ofType(DASHBOARD_LOAD_OK) .waitUntil(action$.ofType(APP_LO
action$
.ofType(DASHBOARD_LOAD_OK)
.waitUntil(action$.ofType(APP_LOAD_OK).first())
.mapTo(...)
有人知道我如何用有效的RxJS来表达它吗?我想避免实现一个新的操作符,因为我认为我的RxJS知识还不够好,但结果比我想象的要简单。我会保持开放,以防有人有更好的解决方案。下面您可以找到代码
Observable.prototype.waitUntil = function(trigger) {
const source = this;
let buffer = [];
let completed = false;
return Observable.create(observer => {
trigger.subscribe(
undefined,
undefined,
() => {
buffer.forEach(data => observer.next(data));
buffer = undefined;
completed = true;
});
source.subscribe(
data => {
if (completed) {
observer.next(data);
} else {
buffer.push(data);
}
},
observer.error.bind(observer),
observer.complete.bind(observer)
);
});
};
如果您想在第一个应用程序加载确认后接收每个仪表板加载确认,您只需使用:
这只会在第一个应用程序加载确定后才开始发送仪表板加载确定操作,之前的所有操作都将被忽略。您可以将
与latestfrom
一起使用,因为它将等待两个源至少发射一次,然后再发射。如果使用仪表板\u LOAD\u OK
作为主要来源:
action$.ofType(DASHBOARD_LOAD_OK)
.withLatestFrom(action$.ofType(APP_LOAD_OK) /*Optionally*/.take(1))
.mapTo(/*...*/);
这允许您在仪表板“加载”正常多次触发的情况下保持发射。我也考虑过这个解决方案。问题是,最初(在页面加载时),两个异步“任务”同时启动,因此它们可以按任意顺序完成。这意味着有时加载动画永远不会完成(如果DASHBOARD\u LOAD\u OK首先到达)。如果您只要求它们发射一次,那么您可以使用
Rx.Observable.zip(action$.ofType(DASHBOARD\u LOAD\u OK),action$.ofType(APP\u LOAD\u OK))。获取(1).Map/**/)
此实现中有几个危险,您应该注意:a)您没有清理您创建的订阅(x2),要成为一名优秀的操作员,您应该返回您在create
中创建的订阅,b)buffer
和completed
是在每次调用而不是每次订阅时创建的,这是一种共享状态,对于冷的可观察对象来说没有bueno(提示尝试多次订阅此流。您可能会看到一些奇怪的行为)。您是对的,非常感谢您将其清除。:)我没有花那么多心思,我只是很高兴我终于找到了一些解决办法。(我可能会在以后有更多时间时编辑它,或者如果您愿意,也可以自己编辑)
action$.ofType(DASHBOARD_LOAD_OK)
.withLatestFrom(action$.ofType(APP_LOAD_OK) /*Optionally*/.take(1))
.mapTo(/*...*/);