Javascript 使用可观测数据的旧式回调同步
我有以下场景-4个回调函数A、B、C、D,它们是从老式的库中调用的(在库中使用一些API请求,因此执行时间未知/随机,但结果的正确顺序(按完成任务时间)对我来说很重要)-我想使用rxjs将返回的数据同步到一个可观察的结果字符串Javascript 使用可观测数据的旧式回调同步,javascript,rxjs,Javascript,Rxjs,我有以下场景-4个回调函数A、B、C、D,它们是从老式的库中调用的(在库中使用一些API请求,因此执行时间未知/随机,但结果的正确顺序(按完成任务时间)对我来说很重要)-我想使用rxjs将返回的数据同步到一个可观察的结果字符串 function getData() { // --- BELOW Part can be EDIT --- let obs = new ReplaySubject(1); // this is example you can use an type f
function getData() {
// --- BELOW Part can be EDIT ---
let obs = new ReplaySubject(1); // this is example you can use an type
function A(n) {
let r= 'A'.repeat(n);
}
function B(n) {
let r= 'B'.repeat(n);
}
function C(n) {
let r= 'C'.repeat(n);
}
function D(n) {
let r= 'D'.repeat(n);
obs.next(r);
}
// --- BELOW Part can NOT be edit ---
runLib(A,B,C,D)
return obs
}
在下面的代码段中,finalResult
的值是DDDDD
,这是错误的。finalResult
字符串的正确值应为aadddccccbbb
//设置-不编辑下面的代码
常数{of,Observable,ReplaySubject}=rxjs;
const{map,switchMap,delay}=rxjs.operators;//例子
//模拟库函数
函数libA(callback){setTimeout(=>callback(2),1000);}
函数libB(callback){setTimeout(=>callback(3),3000);}
函数libC(callback){setTimeout(=>callback(4),2000);}
函数libD(callback){setTimeout(=>callback(5),1500);}
函数runLib(cA、cB、cC、cD){
libA(cA);libB(cB);libC(cC);libD(cD);
}
getData().subscribe(最终结果=>{
console.log(finalResult)//这里的结果是错误的!
},e=>{},=>console.log('finished-unsubscribed');
函数getData(){
//---下面的部分可以编辑---
设obs=newreplaysubject(1);//这是一个示例,您可以使用diffrend observale类
函数A(n){
设r='A'。重复(n);
}
功能B(n){
设r='B'。重复(n);
}
函数C(n){
设r='C'。重复(n);
}
函数D(n){
设r='D'。重复(n);
obs.next(r);
}
//---下面的部分不能编辑---
runLib(A,B,C,D)
返回obs
}
在这种情况下,最好将库函数包装为返回可观察的,然后使用forkJoin
等待所有结果
我获取了您的代码并对其进行了修改以获得所需的结果,您需要:
在每个回调中,将结果发送给主题
返回一个可观察的
,等待n
发射-在本例中为4
将排放映射到单个字符串中
最后的getData
函数如下所示:
函数getData(){
//---下面的部分可以编辑---
const result$:Subject=new Subject();
const obs=result$.asObservable().pipe(
bufferCount(4),//或任何所需的回调次数
映射((结果:字符串[])=>results.join(“”))
);
函数A(n){
让r=“A”。重复(n);
结果$.next(r);
}
功能B(n){
让r=“B”。重复(n);
结果$.next(r);
}
函数C(n){
让r=“C”。重复(n);
结果$.next(r);
}
函数D(n){
让r=“D”。重复(n);
结果$.next(r);
}
//---下面的部分不能编辑---
runLib(A,B,C,D);
返回obs;
}
您可以在代码段中找到完整的代码,也可以在下面的代码段中找到完整的代码
//设置-不编辑下面的代码
const{Subject}=rxjs;
const{take,bufferCount,map}=rxjs.operators;//例子
//模拟库函数
函数libA(callback){setTimeout(=>callback(2),1000);}
函数libB(callback){setTimeout(=>callback(3),3000);}
函数libC(callback){setTimeout(=>callback(4),2000);}
函数libD(callback){setTimeout(=>callback(5),1500);}
函数runLib(cA、cB、cC、cD){
libA(cA);libB(cB);libC(cC);libD(cD);
}
getData().subscribe(最终结果=>{
console.log(finalResult)//这里的结果是错误的!
},e=>{},=>console.log('finished-unsubscribed');
函数getData(){
//---下面的部分可以编辑---
const result$=新主题();
函数A(n){
让r=“A”。重复(n);
结果$.next(r);
}
功能B(n){
让r=“B”。重复(n);
结果$.next(r);
}
函数C(n){
让r=“C”。重复(n);
结果$.next(r);
}
函数D(n){
让r=“D”。重复(n);
结果$.next(r);
}
const obs=结果$.pipe(
bufferCount(4),//或任何所需的回调次数
以(1)为例,
映射(结果=>results.join`)
);
//---下面的部分不能编辑---
runLib(A,B,C,D);
返回obs;
}
以下内容如何:(我喜欢@Tal Ohana的
答案,但他的解决方案中的受试者永远不会下注取消订阅,这可能会导致内存不足)
函数getData(){
设obs=新主题();
函数A(n:编号){
设r='A'。重复(n);
obs.next(r);
}
功能B(n:编号){
设r='B'。重复(n);
obs.next(r);
}
函数C(n:编号){
设r='C'。重复(n);
obs.next(r);
}
函数D(n:编号){
设r='D'。重复(n);
obs.next(r);
}
runLib(A,B,C,D)
回油管(
扫描((acc,值)=>acc+值),
以(4)为例,
最后()
)
}
谢谢-回答得很好-我编辑了你的答案,并将代码段改写为纯JS:)@RafiHenig在这个解决方案中,我们应该做什么来在正确的时间取消订阅?@RafiHenig实际上这不是问题,因为我可以在let subscriber=getData()之后以标准方式取消订阅。因此,退订不是我问题的重点。我可以取消订阅内部订阅(当结果准备好时)2。如果我在其他函数中使用getData().subscribe
,那么在它完成工作之后,它内部将没有对已用对象的引用,垃圾收集器应该删除所有-Ithink@RafiHenig他可以使用take
操作员-取消订阅-我更新他的答案-问题已经解决。您能使用问题的片段并在您的答案中创建可运行的示例吗?(进入回答->编辑(在底部)查看完整的代码片段)你在Tal Ohana回答中的评论中说他在取消订阅方面有问题-我在那里问你如何解决-你知道怎么做吗?在你的回答中,你也从来没有退订过obs observable,所以这里可能也有类似的问题。。。(?)我使用function getData() {
let obs = new Subject<string>();
function A(n: number) {
let r = 'A'.repeat(n);
obs.next(r);
}
function B(n: number) {
let r = 'B'.repeat(n);
obs.next(r);
}
function C(n: number) {
let r = 'C'.repeat(n);
obs.next(r);
}
function D(n: number) {
let r = 'D'.repeat(n);
obs.next(r);
}
runLib(A, B, C, D)
return obs.pipe(
scan((acc, value) => acc + value),
take(4),
last()
)
}