简体   繁体   English

如何确保一个订阅在另一个订阅之前完成?

[英]How do I make sure one Subcription finishes before another?

globleVariable: any;

ngOnInit() {
    // This doesn't work. methodTwo throws error saying "cannot read someField from null. "
    this.methodOne();
    this.methodTwo();
}

methodOne() {
    this.firstService.subscribe((res) => { this.globleVariable = res });
}

methodTwo() {
    this.secondService.subscribe((res) => { console.log(this.globleVariable.someField) });
}

As shown above, methodOne set the value of globleVariable and methodTwo uses it, therefore the former must finish running before the latter.如上所示, methodOne设置了methodTwo globleVariable它,因此前者必须先于后者运行完毕。

I am wondering how to achieve that.我想知道如何实现这一目标。

Instead of subscribing in the methods, combine them into one stream and subscribe to that in ngInit() .不要订阅方法,而是将它们组合成一个 stream 并在ngInit()中订阅它。 You can use tap to perform the side effect of updating globaleVariable that you were previously performing in subscribe() .您可以使用tap来执行您之前在subscribe()中执行的更新globaleVariable的副作用。

In the example below the "methods" are converted into fields since there is no reason for them to be methods anymore (you can keep them as methods if you want).在下面的示例中,“方法”被转换为字段,因为它们不再是方法(如果需要,您可以将它们保留为方法)。 Then the concat operator is used to create a single stream, where methodOne$ will execute and then when it's complete, methodTwo$ will execute.然后使用concat运算符创建单个 stream,其中 methodOne $将执行,然后当它完成时, methodTwo$将执行。

Because concat executes in order, you are guaranteed that globaleVariable will be set by methodOne$ before methodTwo$ begins.因为concat按顺序执行,所以可以保证globaleVariable将在methodTwo$开始之前由 methodOne $设置。

globleVariable: any;
methodOne$ = this.someService.pipe(tap((res) => this.globleVariable = res));
methodTwo$ = this.someService.pipe(tap((res) => console.log(this.globleVariable.someField));

ngOnInit() {
  concat(this.methodOne$, this.methodTwo$).subscribe();
}

You can create a subject for which observable 2 will wait to subscribe like below:-您可以创建一个主题,observable 2 将等待订阅,如下所示:-

globalVariable: any;

subject: Subject = new Subject();

methodOne() {
    this.someService.subscribe((res) => { this.globleVariable = res; this.subject.next(); });
}

methodTwo() {
    this.subject.pipe(take(1), mergeMap(() => this.someService)).subscribe((res) => { 
          console.log(this.globleVariable.someField) });
}

The only way to guarantee a method call after a subscription yields is to use the subscription callbacks.在订阅产生后保证方法调用的唯一方法是使用订阅回调。

Subscriptions have two main callbacks a success and a failure.订阅有两个主要回调成功和失败。

So the way to implement a method call after the subscription yeilds is to chain it like this:所以在订阅 yields 之后实现方法调用的方法是像这样链接它:

globleVariable: any;

ngOnInit() {
    this.methodOne();
}

methodOne() {
    this.someService.subscribe((res) => {
       this.globleVariable = res
       this.methodTwo(); // <-- here, in the callback
    });
}

methodTwo() {
    this.someService.subscribe((res) => { console.log(this.globleVariable.someField) });
}

You might want to chain the calls with some other rxjs operators for a more standard usage.您可能希望将调用与其他一些rxjs 操作员链接起来以获得更标准的用法。

ngOnInit() {
  this.someService.method1.pipe(
    take(1),
    tap(res1 => this.globleVariable = res1)
    switchmap(res1 => this.someService.method2), // <-- when first service call yelds success
    catchError(err => { // <-- failure callback
                console.log(err);
                return throwError(err)
            }),
  ).subscribe(res2 => { //  <-- when second service call yelds success
    console.log(this.globleVariable.someField) });
  });
}

Please remember to complete any subscriptions when the component is destroyed to avoid the common memory leak .请记住在组件销毁时完成任何订阅,以避免常见的memory 泄漏

my take,我的看法,

so it's a bit confusing when you use same service that throws different results, so instead of someService I used firstService and secondService here.所以当你使用相同的服务但会抛出不同的结果时会有点混乱,所以我在这里使用firstServicesecondService而不是someService

this.firstService.pipe(
  switchMap(globalVariable) => 
    this.secondService.pipe(
      map(fields => Object.assign({}, globalVariable, { someField: fields }))
    )
  )
).subscribe(result => {
  this.globalVariable = result;
})

What I like about this approach is that you have the flexibility on how you want to use the final result as it is decoupled with any of the property in your class.我喜欢这种方法的一点是,您可以灵活地使用最终结果,因为它与 class 中的任何属性都解耦了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 确保第一个 ajax 函数在第二个之前完成 - Make sure first ajax function finishes before second one 如何确保在导航到另一个页面之前完成减速器响应操作? - How do I make sure that reducer response action is done before navigating to another page? 如何确保一个接一个的函数调用 - How do I make sure one function call happens after another 如何确保在深度模块化的Backbone,Require.js和D3应用程序中先调用某个函数? - How do I make sure a function will be called before another in a deeply modularized Backbone, Require.js and D3 app? 如何确保在主体渲染完成之前进行document.write操作? - How to make sure document.write action takes place before body rendering finishes? 如何确保至少选中一个复选框? - How do I make sure that at least one checkbox is checked? 我如何为此创建一个循环,使其在执行下一个 if 语句之前完成每个 if 语句? - How do I make a loop for this in a way that it finishes each of the if statement before going to the next? 如何确保XMLHttpRequest在for循环中完成? - How to make sure XMLHttpRequest finishes inside for loop? 如何确保在初始视图加载之前完成组件中的 oData 读取 - How to make sure oData read in component finishes before Initial View load 如何确保fs.createWriteStream在函数继续执行之前完成; 仅保存一部分图像 - How to make sure fs.createWriteStream finishes before function continues; only fraction of image being saved
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM