Observables vs Promises-处理,然后返回异步结果

时间:2019-06-12 10:37:17

标签: angular promise rxjs

我在AngularJS中使用诺言有很多经验,现在正努力使我在Angular中使用Observable。

我对单个异步结果的承诺 like -它们似乎非常适合此用例-但Angular似乎热衷于将Observables用于所有内容,因此我现在尝试尽力理解使用此模式的实践。

下面是一个示例,说明如何使用诺言链实现某些目标。目标是:

    MyClass.value
  1. doSomethingAsync()时应始终设置
  2. 呼叫者-在这种情况下,doSomethingElse()应该能够与 doSomethingAsync() 是否想要等待直到完成 ,然后再使用结果

export class MyClass {
    private value;

    public doSomethingAsync() {
        return someAsyncCall()
            .then(value => {
                this.value = value
            });
    }
}

export class MyOtherClass {
    public doSomethingElse() {
        const myObj = new MyClass();
        let myValue;

        myObj
            .doSomethingAsync()
            .then(value => {
                myValue = value
            });
    }
}

我试图弄清楚如何使用Observables。

我可以在.pipe()中将tap()doSomethingAsync()一起使用来捕获值,但是问题是,除非doSomethingElse()调用{{1 }}上返回的Observable。我不想让subscribe()依赖于呼叫者接下来的工作。

可以调用doSomethingAsync()中的subscribe()来捕获值,但是随后我不再有Observable返回。所以我想我可能不得不做这样的事情:

doSomethingAsync()

但是,这似乎过于复杂,因为我现在也必须弄乱主题,并有效地跟踪两个不同的流。

有人可以建议这样做的更好方法吗?在我看来,用诺言处理起来要容易得多……?

2 个答案:

答案 0 :(得分:0)

正如您所说,他们非常热衷于使用rxjs。对于经典的后端,您只想调用一次,解决一个承诺,就是这样,将可观察对象转换为一个承诺,并根据设计需求返回您的承诺;要实现这一目标,请在Observable上使用rxjs中的toPromise()

保持Observable的想法是,您观察一个端点,该端点会在数据发生变化时即时返回值,并且您可以随时接收它们,一旦完成,您就退订(离开视图或类似的视图) 。例如,一些使用websocket的api或一些实时后端(例如Firebase)。但这对于经典的后端没有意义,在传统的后端中,您将其称为端点->得到结果->就这样。因为最后,每次您想得到那里的东西时,都必须打一个新电话。

然后您的示例如下所示:

export class MyClass {
    private value;

    public doSomethingAsync() {
        return someAsyncCall().toPromise();
    }
}

export class MyOtherClass {
    public doSomethingElse() {
        const myObj = new MyClass();
        let myValue;

        myObj
            .doSomethingAsync()
            .then(value => {
                myValue = value
            });
    }
}

答案 1 :(得分:0)

好的,我已经弄清楚了现在该怎么做。但是,我现在得出结论(请参见下文),这并不是使用RxJS的好方法...

export class MyClass {
    private value;

    public doSomethingAsync() {
        const observable = someAsyncCall()
            .pipe(
                tap(value => {
                    this.value = value;
                }),
                share()
            );

        observable.subscribe();

        return observable;
    }
}

export class MyOtherClass {
    public doSomethingElse() {
        const myObj = new MyClass();
        let myValue;

        myObj
            .doSomethingAsync()
            .subscribe(value => {
                myValue = value
            });
    }
}

工作方式:

  1. 订阅doSomethingAsync()意味着总是触发异步源操作。
  2. 使用share()意味着呼叫者也可以订阅而无需重新触发源。 share()在后​​台使用主题工厂,这也意味着调用方可以选择重试整个序列。
  3. 使用tap()中的subscribe()(而不是doSomethingAsync())来捕获值,这意味着如果调用方重试,它将被重新捕获-这使所有状态保持一致。 / li>

好处:

    如果我们对结果不感兴趣,则不必订阅
  1. doSomethingAsync(),它仍然会执行操作。
  2. MyClass负责维护自己的状态-MyClass的状态不受调用方是否执行.subscribe()功能的影响。 / li>

缺点:

  1. 这是非典型的行为-观察者通常通常必须先订阅才能这样做,因此这超出了预期。
  2. 如果呼叫者重试订阅,
  3. MyClass 的状态仍会受到影响-这是为了保持状态的一致性而设计的,但这确实意味着我还没有完全 保留了封装。

结论:

我现在得出的结论是,做到这一点的“正确”方法-不违背我认为Observables应该起作用的方式-实际上是依靠调用者来执行订阅,即:

export class MyClass {
    private value;

    public doSomethingAsync() {
        return someAsyncCall()
            .pipe(
                tap(value => {
                    this.value = value;
                })
            );
    }
}

export class MyOtherClass {
    public doSomethingElse() {
        const myObj = new MyClass();
        let myValue;

        myObj
            .doSomethingAsync()
            .subscribe(value => {
                myValue = value
            });
    }
}

好处:

  1. 与以前的解决方案相比,它的代码更少。
  2. 由于doSomethingAsync()方法返回一个Observable,我认为通常的期望是在您对结果调用.subscribe()之前什么都不会发生。
  3. 呼叫者可以重试。
  4. 我认为在这种情况下,返回的Observable可以合法地视为MyClass的“朋友”,因此可以(通过.subscribe()方法修改其状态)。

缺点:

  1. 仍然比承诺的代码多得多的代码。
  2. 从概念上讲,比诺言更难理解:
    • 需要了解pipe()tap()subscribe()
    • 至少需要对异步流处理有基本的了解。
    • 为了保证,您只需要了解如何使用promise.then()将单个异步调用链接在一起,在我看来这是一个简单得多的概念。
    • RxJS的
    • 大多数处理功能是多余的,并且只会增加复杂性-如果您实际上不处理事件流 >。
  3. 无论是否关心异步操作的结果(或完成情况),调用者都必须调用subscribe()才能使事情发生。