主题订阅,等到函数执行完成

时间:2020-10-09 20:56:23

标签: asynchronous rxjs

我对可观察物有疑问。我的情况是,我订阅了此主题,并且希望在可观察到的成功响应中运行一个函数。一旦我的函数(foo)完成(此函数必须完成才能继续逻辑以成功完成响应),我想将.next()方法传递给另一个主题。我的问题是,我不知道该如何等待我的函数foo完成并返回值。如果我在另一个主题上对.next()方法调用setTimeout,则一切正常。我只是想避免setTimeout。 我的代码的架构是:

def program(num):
    for i in range(num):
        print("The number is", i)

runs = 3
for _ in range(runs):
    program(5)

如果我在订阅中使用我的代码,如下所示:

this.customService.customSubject$.subscribe((response) => {
  this.someValueNeededInFoo = response;    
  this.foo(); //I need to wait for this function to be executed until I move on
  this.customService2.anotherSubject$.next(true); //That will be great if I can wait for this as well
  this.customService2.thirdSubject$.next(response); //This should invoke last
});

foo() {
 //do some logic stuff 
 return value;
}

然后一切正常。我想避免使用setTimeout,因为就我而言,它不是真正可靠的。谁能指导我,在这里我该怎么做,以进行一系列这些函数调用? 谢谢!

1 个答案:

答案 0 :(得分:0)

您所关注的不是观察性问题,而是this.foo()是一种异步方法,这意味着它返回了诺言。

您只需在调用.then()之后将逻辑放在foo()块中。这样可以确保在foo完成后执行它:

this.customService.customSubject$.subscribe(response => {
  this.someValueNeededInFoo = response;    
  this.foo().then(valFromFoo => {
     this.customService2.anotherSubject$.next(true);
     this.customService2.thirdSubject$.next(response);
  })
});

您可以选择使用async/await语法,而不使用.then()。以下代码与上面的示例等效:

this.customService.customSubject$.subscribe(async response => {
  this.someValueNeededInFoo = response;    
  await this.foo();
  this.customService2.anotherSubject$.next(true);
  this.customService2.thirdSubject$.next(response);
  })
});

我想提到,通常不需要创建一堆主题以从其他流中发出值。通常,您可以相互定义流。

代替做这样的事情:

docIdSubject$ = new Subject<string>();
documentSubject$ = new Subject<Document>();

this.someService.id$.subscribe(
  id => this.docIdSubject$.next(id)
);

this.docIdSubject$.subcribe(
  docId => {
    this.docService.getDocument(docId).subscribe(
      document => this.documentSubject$.next(document)
    );
  );
);

您可以从根本不需要对象的可观察源定义可观察对象。

docId$ = this.someService.id$;
document$ = this.docId$.pipe(
   switchMap(id => docService.getDocument(id))
);

您可以根据需要使用管道运算符来转换流。请注意,没有内部订阅。我发现将所有数据转换逻辑以声明方式放入流定义(在.pipe()内)要干净得多,而在实际订阅中只需要做很少的工作。

现在注意,您可以执行document$.subscribe()