javascript 使用 RxJS 链接 promise
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29946512/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Chaining promises with RxJS
提问by Pathsofdesign
I'm new to RxJS and FRP in general. I had the idea of converting an existing promise chain in my ExpressJS application to be an observable for practice. I am aware that this probably isn't the best example but maybe someone can help shed some light.
我是 RxJS 和 FRP 的新手。我的想法是将 ExpressJS 应用程序中现有的承诺链转换为可观察的实践。我知道这可能不是最好的例子,但也许有人可以帮助阐明一些观点。
What I'm trying to do:
我正在尝试做的事情:
- I have two promises - prom1 and prom2
- I want prom1 to run before prom2
- If prom1 sends a reject(err), I want to cancel prom2 before it starts.
- I want the error message prom1 returns to be available to the onError method on the observer.
- 我有两个承诺 - prom1 和 prom2
- 我希望 prom1 在 prom2 之前运行
- 如果prom1 发送reject(err),我想在prom2 开始之前取消它。
- 我希望 prom1 返回的错误消息可用于观察者上的 onError 方法。
var prom1 = new Promise(function(resolve, reject) {
if (true) {
reject('reason');
}
resolve(true);
});
var prom2 = new Promise(function(resolve, reject) {
resolve(true);
});
// What do I do here? This is what I've tried so far...
var source1 = Rx.Observable.fromPromise(prom1);
var source2 = source1.flatMap(Rx.Observable.fromPromise(prom2));
var subscription = source2.subscribe(
function (result) { console.log('Next: ' + result); },
// I want my error 'reason' to be made available here
function (err) { console.log('Error: ' + err); },
function () { console.log('Completed'); });
回答by Bogdan Savluk
If I understood what you are trying to do - you need to create two deferred observables from functions that return promises and concat them:
如果我理解你想要做什么 - 你需要从返回承诺的函数中创建两个延迟的可观察对象并将它们连接起来:
var shouldFail = false;
function action1() {
return new Promise(function (resolve, reject) {
console.log('start action1');
if (shouldFail) {
reject('reason');
}
resolve(true);
});
}
function action2() {
return new Promise(function (resolve, reject) {
console.log('start action2');
resolve(true);
});
}
var source1 = Rx.Observable.defer(action1);
var source2 = Rx.Observable.defer(action2);
var combination = Rx.Observable.concat(source1, source2);
var logObserver = Rx.Observer.create(
function (result) {
console.log('Next: ' + result);
},
function (err) {
console.log('Error: ' + err);
},
function () {
console.log('Completed');
});
then for normal case:
那么对于正常情况:
combination.subscribe(logObserver);
// start action1
// Next: true
// start action2
// Next: true
// Completed
And case where fisrt promise fails:
以及第一个承诺失败的情况:
shouldFail = true;
combination.subscribe(logObserver);
// start action1
// Error: reason
回答by Daniel Bachler
flatMap turns an Observable of Observables into an Observable. It's used in many examples with Promises because often you have an observable and in the map function you want to create a promise for each "item" the observable emmits. Because every fromPromise call creates a new Observable, that makes it an "observable of observables". flatMap reduces that to a "flat" observable.
flatMap 将 Observable 的 Observable 变成 Observable。它在许多带有 Promise 的示例中使用,因为通常您有一个 observable,并且在 map 函数中,您希望为 observable 发出的每个“项目”创建一个承诺。因为每个 fromPromise 调用都会创建一个新的 Observable,这使它成为“可观察的可观察对象”。flatMap 将其减少为“平面”可观察对象。
In your example you do something different, you turn a single promise into an observable and want to chain it with another observable (also created form a single promise). Concat does what you are looking for, it chains two observables together.
在你的例子中,你做了一些不同的事情,你将一个单一的承诺变成了一个可观察的,并希望将它与另一个可观察的(也是从单个承诺中创建的)链接起来。Concat 做你正在寻找的事情,它将两个可观察对象链接在一起。
The error case will work as you would expect.
错误情况将按您的预期工作。
回答by Nick Shulzhenko
Observable.forkJoin
works great here receiving array of other Observables.
Observable.forkJoin
在这里接收其他 Observable 数组效果很好。
Rx.Observable.forkJoin([this.http.get('http://jsonplaceholder.typicode.com/posts'), this.http.get('http://jsonplaceholder.typicode.com/albums')]).subscribe((data) => {
console.log(data);
});