主题发出后的RxJS执行顺序

时间:2019-07-12 22:39:05

标签: javascript angular typescript rxjs

我想了解对主题的“下一次”调用之后的代码执行顺序。

背景:我有3个类(将它们称为HaveSubject,HaveSubscription1,HaveSubscription2)。 HaveSubject需要通过预订了HS1和HS2的Subject来告诉HS1和HS2做某事。必须先完成其任务,然后HaveSubject才能继续执行somethingVeryImportant方法。

伪代码:

class HaveSubject {
    // Angular service
    public mySubject$: Subject<string> = new Subject<string>();

    public codeImExecuting() {
        this.mySubject$.next('input for tasks')
        this.somethingVeryImportant();
    }

    private somethingVeryImportant() {
        // stuff
    }
}

class HaveSubscription1 {
    // Angular service
    constructor(private hs: HaveSubject) {
        this.hs.mySubject$.subscribe(inputStr => {
            // did I do this before somethingVeryImportant is called?
        });
    }
}

class HaveSubscription2 {
    // Angular service
    constructor(private hs: HaveSubject) {
        this.hs.mySubject$.subscribe(inputStr => {
            // did I do this before somethingVeryImportant is called?
        });
    }
}

我的问题是:在继续执行somethingVeryImportant方法之前,确保HS1和HS2已执行附加到其订阅的代码的最佳方法是什么?如果操作顺序是:HaveSubject在主题上调用“ next”-> HS1和HS2执行任务-> HaveSubject继续执行下一行代码,这很重要,那么我没有问题。我只是不确定在订阅中收到订阅中的“下一个”项目后立即执行订阅。

注意:有一些我通常无法做的事情,例如将HaveSubject注入到另外两个中,因为其他两个是动态创建的(即,我可能没有,没有一个或两个HaveSubscriptionX ,不清楚会创建多少,而这些是组件提供的Angular服务,而不是根目录...)。

有想法吗?

2 个答案:

答案 0 :(得分:0)

HaveSubscription#中完成边工作时最简单的呼叫事件(不理想的是大量重复的运行检查第二个选项)

class HaveSubject {
    // Angular service
    public mySubject$: Subject<string> = new Subject<string>();
    public mySubjectDone$: Subject<void> = new Subject<void>();

    public constructor() {
        this.mySubjectDone$.subscribe(this.somethingVeryImportant.bind(this));
    }

    public codeImExecuting() {
        this.mySubject$.next('input for tasks')
    }

    private somethingVeryImportant() {
        // stuff
    }
}

class HaveSubscription1 {
    // Angular service
    constructor(private hs: HaveSubject) {
        this.hs.mySubject$.subscribe(inputStr => {
            // did I do this before somethingVeryImportant is called?
            hs.mySubjectDone$.next()
        });
    }
}

class HaveSubscription2 {
    // Angular service
    constructor(private hs: HaveSubject) {
        this.hs.mySubject$.subscribe(inputStr => {
            // did I do this before somethingVeryImportant is called?
            hs.mySubjectDone$.next()
        });
    }
}

或者如果您不想从HaveSubscription#进行任何操作,则会触发延迟操作

class HaveSubject {
    // Angular service
    public mySubject$: Subject<string> = new Subject<string>();

    public constructor() {
        this.mySubject$.pipe(
            debounceTime(16) // delay or auditTime, debounceTime, ...
        ).subscribe(this.somethingVeryImportant.bind(this));
    }

    public codeImExecuting() {
        this.mySubject$.next('input for tasks')
    }

    private somethingVeryImportant() {
        // stuff
    }
}

class HaveSubscription1 {
    // Angular service
    constructor(private hs: HaveSubject) {
        this.hs.mySubject$.subscribe(inputStr => {
            // did I do this before somethingVeryImportant is called?
        });
    }
}

class HaveSubscription2 {
    // Angular service
    constructor(private hs: HaveSubject) {
        this.hs.mySubject$.subscribe(inputStr => {
            // did I do this before somethingVeryImportant is called?
        });
    }
}

如果您有某种版本控制机制可以对HaveSubscription#中所做的更改做出反应,则可以执行以下操作:

this.mySubject$.pipe(
  map(this.calculateVersion),
  distinctUntilChanged(),
).subscribe(this.somethingVeryImportant.bind(this));

答案 1 :(得分:0)

因此,由于流程如此,您似乎已经做出了一些可疑的体系结构决定

  1. 服务1函数从可观察的位置执行并发出
  2. 服务2/3 / etc的订户向服务1的可观察执行代码产生一些输出或副作用
  3. 服务1的功能需要执行,具体取决于服务2/3 / etc功能的某些输出或副作用

这要求主题对象了解其观察者,这与rxjs哲学的相反。理想的解决方案是解决这些体系结构问题。很难说出如何做到这一点,而又不了解事情的发生方式或原因,总体目标是什么。

但是,您可以以一种非常可靠的方式完成此操作,您需要在第一个函数上添加一些主题,以表明相关服务已完成:

// BAD
this.strike = function() {
    this.health -= this.damage
    console.log(this.health)
    if(this.aggro === true) { setTimeout(this.strike(), this.ratio); } //<== This line crashes your comp because it's just recursing in to 'strike' calls
}

// OK
this.strike = function() {
    this.health -= this.damage
    console.log(this.health)
    if(this.aggro === true) { setTimeout(this.strike.bind(this), this.ratio); } //<= we make sure 'this' will ref the right object here, and pass the REFERENCE of the method to setTimeout, not the RESULT of a call
}

// Also OK maybe?
this.strike = function() {
    this.health -= this.damage
    console.log(this.health)
    if(this.aggro === true) { setTimeout(this.strike, this.ratio); }
}.bind(this)

,并让mySubject $的观察者完成后调用imDone()。