将承诺转换为可观察的

Kri*_*ram 162 rxjs firebase firebase-authentication angular

我试图围绕着可观察者.我喜欢observables解决开发和可读性问题的方式.在我读到的时候,好处是巨大的.

关于HTTP和集合的可观察量似乎是直截了当的.我怎样才能将这样的东西转换为可观察的模式.

这是来自我的服务组件,用于提供身份验证.我希望它能像Angular2中的其他HTTP服务一样工作 - 支持数据,错误和完成处理程序.

firebase.auth().createUserWithEmailAndPassword(email, password)
  .then(function(firebaseUser) {
    // do something to update your UI component
    // pass user object to UI component
  })
  .catch(function(error) {
    // Handle Errors here.
    var errorCode = error.code;
    var errorMessage = error.message;
    // ...
  });
Run Code Online (Sandbox Code Playgroud)

这里的任何帮助将不胜感激.我唯一的替代解决方案是创建EventEmitters.但我想这是在服务部门做事的一种可怕方式

Gui*_*ume 229

如果您使用的是RxJS 6.0.0:

import { from } from 'rxjs';
const observable = from(promise);
Run Code Online (Sandbox Code Playgroud)

  • 这个答案是不正确的,它只是有时有效。Promise 是急切的,而 observables 是惰性的(直到订阅才开始)。使用此解决方案,即使没有“.subscribe()”,promise 也已经开始,因此它的行为不像可观察的。请参阅答案/sf/answers/4855225021/以获得更好的解决方案。 (11认同)
  • 使用6.3.3的`from`方法返回可观察到的值,但它会将Promise作为值发送给订阅。:( (6认同)
  • 请小心使用此解决方案,因为它可能会导致未处理的承诺拒绝,这可能会破坏您的代码!如果您使用 from 运算符,则必须在 from 运算符内的 Promise 中处理您的 Promise 拒绝(使用 .catch()),否则 Promise 可能会执行并抛出错误,而其包装的可观察对象尚未被订阅,并且如果您的错误处理通过管道传递给可观察的它不会捕获错误!(我更喜欢使用 defer 来代替并从可观察到的集中处理错误)。 (3认同)

God*_*her 110

试试这个:

import 'rxjs/add/observable/fromPromise';
import { Observable } from "rxjs/Observable";

const subscription = Observable.fromPromise(
    firebase.auth().createUserWithEmailAndPassword(email, password)
);
subscription.subscribe(firebaseUser => /* Do anything with data received */,
                       error => /* Handle error here */);
Run Code Online (Sandbox Code Playgroud)

您可以在此处找到fromPromise运算符的完整参考

  • `import'rxjs/add/observable/fromPromise';` (45认同)
  • `import {Observable} from"rxjs/Observable";`:) (15认同)

Llo*_*iol 75

将 Promise 转换为 Observable 的正确模式defer是使用andfrom运算符:

import { defer, from } from 'rxjs';
    
const observable$ = defer(() => from(myPromise()));
Run Code Online (Sandbox Code Playgroud)

为什么我们需要defer运营商?

Promise 是急切的,这意味着当被调用时它们会立即触发。这与可观察量的工作方式相反。Observables 是惰性的,它们仅在.subscribe()被调用时才会被触发。这就是我们需要始终将其包装到运算符中的原因defer。操作from员不做这项工作,所以defer总是需要


fri*_*doo 22

使用from直接转换之前创建的承诺,以可观察到的。

import { from } from 'rxjs';

// getPromise() will only be called once
const observable$ = from(getPromise());
Run Code Online (Sandbox Code Playgroud)

创建Observable时,Promise的主体正在执行或已解决。如果内部Promise已解决,则Observable的新订户将立即获得其值(getPromise()不会再次调用)。

推迟

使用defer具有无极工厂功能输入到无极的创建和转换推迟到可观察到的。

import { defer } from 'rxjs';

// getPromise() will be called every time someone subscribes to the observable$
const observable$ = defer(() => getPromise());
Run Code Online (Sandbox Code Playgroud)

与之不同的from是,defer等待订户,然后才通过调用给定的Promise工厂函数来创建新的Promise。当您要创建一个Observable但又不想立即执行内部Promise时,这很有用。内部的Promise仅在有人订阅Observable时执行。每个订户还将获得自己的新Observable。

fromdefer示例之间的区别: https : //stackblitz.com/edit/rxjs-6rb7vf

const getPromise = val => new Promise(resolve => {
  console.log('Promise created for', val);
  setTimeout(() => resolve(`Promise Resolved: ${val}`), 5000);
});

// the execution of getPromise('FROM') starts here, when you create the promise inside from
const fromPromise$ = from(getPromise('FROM'));
const deferPromise$ = defer(() => getPromise('DEFER'));

fromPromise$.subscribe(console.log);
// the execution of getPromise('DEFER') starts here, when you subscribe to deferPromise$
deferPromise$.subscribe(console.log);
Run Code Online (Sandbox Code Playgroud)

其他选择

创造可观测量(如大多数RxJS功能mergeconcatforkJoincombineLatest...)和多家运营商(例如switchMapmergeMapconcatMapcatchError...),也可以直接接受的承诺。

如果仍然使用其中一个,则不from必先包装Promise,尽管您仍可能希望使用它defer来实现仅在订阅上创建Promise的效果。

具体来说,大多数功能使用ObservableInputSubscribableOrPromise定义如下。注意PromiseLike

type ObservableInput<T> = SubscribableOrPromise<T> | ArrayLike<T> | Iterable<T>;

type SubscribableOrPromise<T> = Subscribable<T> | Subscribable<never> | PromiseLike<T> | InteropObservable<T>;
Run Code Online (Sandbox Code Playgroud)

查看RxJS文档实现,以查看您使用的功能是否支持ObservableInputSubscribableOrPromise

  • 我认为差异是资本,谢谢你指出这一点。 (6认同)
  • 感谢分享,很多运营商直接接受承诺!蒂尔 (3认同)