问答中心分类: FIREBASE将 Promise 转换为 Observable
0
匿名用户 提问 35分钟 前

我正试图将我的头包裹在可观察的事物上。我喜欢 observables 解决开发和可读性问题的方式。正如我所读的,好处是巨大的。
HTTP 和集合上的 Observables 似乎是直截了当的。我怎样才能将这样的东西转换为可观察的模式。
这是来自我的服务组件,用于提供身份验证。我希望它能够像 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;
    // ...
  });

在这里的任何帮助将不胜感激。我唯一的替代解决方案是创建EventEmitters。但我想这是在服务部分做事的糟糕方式

Gherman 回复 35分钟 前

我认为这个问题并不特定于 Angular 或 Firebase。它特定于 rxjs。

7 Answers
0
frido 回答 35分钟 前

1 直接执行/转换
利用from直接将之前创建的 Promise 转换为 Observable。

import { from } from 'rxjs';

// getPromise() is called once, the promise is passed to the Observable
const observable$ = from(getPromise());

observable$将是一个热可观察有效地向订阅者重放承诺值。
它是一个热门的 Observable,因为生产者(在本例中为 Promise)是在 Observable 之外创建的。多个订阅者将共享同一个 Promise。如果内部 Promise 已解决,则 Observable 的新订阅者将立即获得其值。
2 每次订阅的延迟执行
利用defer使用 Promise 工厂函数作为输入,以推迟 Promise 的创建和转换为 Observable。

import { defer } from 'rxjs';

// getPromise() is called every time someone subscribes to the observable$
const observable$ = defer(() => getPromise());

observable$将是一个冷可观察.
这是一个冷的 Observable,因为生产者(Promise)是在 Observable 内部创建的。每个订阅者都将通过调用给定的 Promise 工厂函数来创建一个新的 Promise。
这允许您创建一个observable$无需立即创建并执行 Promise,也无需与多个订阅者共享此 Promise。每个订阅者observable$有效地调用from(promiseFactory()).subscribe(subscriber).因此,每个订阅者都会创建自己的新 Promise 并将其转换为新的 Observable,并将自己附加到这个新的 Observable。
3 许多运营商直接接受承诺
大多数组合的 RxJS 运算符(例如merge,concat,forkJoin,combineLatest…)或转换可观察的(例如switchMap,mergeMap,concatMap,catchError…) 直接接受承诺。如果您仍然使用其中之一,则不必使用from首先包装一个承诺(但要创建一个冷观测你可能仍然需要使用defer)。

// Execute two promises simultaneously
forkJoin(getPromise(1), getPromise(2)).pipe(
  switchMap(([v1, v2]) => v1.getPromise(v2)) // map to nested Promise
)

检查文件或者执行查看您使用的运营商是否接受ObservableInput或者SubscribableOrPromise.

type ObservableInput<T> = SubscribableOrPromise<T> | ArrayLike<T> | Iterable<T>;
// Note the PromiseLike ----------------------------------------------------v
type SubscribableOrPromise<T> = Subscribable<T> | Subscribable<never> | PromiseLike<T> | InteropObservable<T>;

和…之间的不同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);

defer可能是大多数人正在寻找的运营商,因为许多应用程序依赖 Observables 来冷却并在订阅时触发数据获取。from但是对于某些用例来说仍然是一个可行的选择,例如,当您想在某个初始化过程中创建一次 Promise,然后通过将被订阅多次的 Observable 传播其值,但不想创建和执行再次向每个订阅者承诺。

Starscream 回复 35分钟 前

我认为差异是资本,感谢您指出。

BobbyTables 回复 35分钟 前

感谢分享,很多运营商直接接受promise! TIL

helhum 回复 35分钟 前

非常感谢你写了这么详细的文章!它不仅帮助我解决了我的问题,还帮助我更好地理解了这些概念。

0
Godfather 回答 35分钟 前

尝试这个:

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 */);

您可以找到对 fromPromise 运算符的完整参考这里.

0
Llorenç Pujol Ferriol 回答 35分钟 前

正确的图案将一个承诺转化为一个可观察的正在使用deferfrom运营商:

import { defer, from } from 'rxjs';
    
const observable$ = defer(() => from(myPromise()));

为什么我们需要defer操作员?
承诺是渴望的,这意味着当被调用时,它们会立即触发。这与可观察对象的工作方式相反。可观察物是懒惰的,它们仅在以下情况下被解雇.subscribe()叫做。这就是我们需要始终将其包装成defer操作员。这from操作员不做这项工作,所以defer总是需要。

0
khizer 回答 35分钟 前

您可以添加一个围绕承诺功能的包装器,以将 Observable 返回给观察者。

  • 创建一个懒惰的可观察使用推迟()运算符允许您仅在观察者订阅时创建 Observable。
import { of, Observable, defer } from 'rxjs'; 
import { map } from 'rxjs/operators';


function getTodos$(): Observable<any> {
  return defer(()=>{
    return fetch('https://jsonplaceholder.typicode.com/todos/1')
      .then(response => response.json())
      .then(json => {
        return json;
      })
  });
}

getTodos$().
 subscribe(
   (next)=>{
     console.log('Data is:', next);
   }
)
0
Jonathan 回答 35分钟 前
import { from } from 'rxjs';

from(firebase.auth().createUserWithEmailAndPassword(email, password))
.subscribe((user: any) => {
      console.log('test');
});

这是一个较短的版本,它结合了上面的一些答案,将您的代码从 Promise 转换为 observable。

janw 回复 35分钟 前

虽然这段代码可以解决这个问题,包括解释解决问题的方式和原因将真正有助于提高帖子的质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。请编辑您添加解释并说明适用的限制和假设的答案。