我正试图将我的头包裹在可观察的事物上。我喜欢 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;
// ...
});
在这里的任何帮助将不胜感激。我唯一的替代解决方案是创建EventEmitter
s。但我想这是在服务部分做事的糟糕方式
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>;
和…之间的不同from
和defer
在一个例子中: 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 传播其值,但不想创建和执行再次向每个订阅者承诺。
我认为差异是资本,感谢您指出。
感谢分享,很多运营商直接接受promise! TIL
非常感谢你写了这么详细的文章!它不仅帮助我解决了我的问题,还帮助我更好地理解了这些概念。
尝试这个:
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 运算符的完整参考这里.
正确的图案将一个承诺转化为一个可观察的正在使用defer
和from
运营商:
import { defer, from } from 'rxjs';
const observable$ = defer(() => from(myPromise()));
为什么我们需要defer
操作员?
承诺是渴望的,这意味着当被调用时,它们会立即触发。这与可观察对象的工作方式相反。可观察物是懒惰的,它们仅在以下情况下被解雇.subscribe()
叫做。这就是我们需要始终将其包装成defer
操作员。这from
操作员不做这项工作,所以defer
是总是需要。
您可以添加一个围绕承诺功能的包装器,以将 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);
}
)
import { from } from 'rxjs';
from(firebase.auth().createUserWithEmailAndPassword(email, password))
.subscribe((user: any) => {
console.log('test');
});
这是一个较短的版本,它结合了上面的一些答案,将您的代码从 Promise 转换为 observable。
我认为这个问题并不特定于 Angular 或 Firebase。它特定于 rxjs。