来自Promise世界,我可以实现一个队列函数,该函数返回一个在前一个Promise结算之前不会执行的Promise。
var promise = Promise.resolve();
var i = 0;
function promiseQueue() {
return promise = promise.then(() => {
return Promise.resolve(++i);
});
}
promiseQueue().then(result => {
console.log(result); // 1
});
promiseQueue().then(result => {
console.log(result); // 2
});
promiseQueue().then(result => {
console.log(result); // 3
});
// -> 1, 2, 3
我试图使用Observables重新创建这个类似队列的函数。
var obs = Rx.Observable.of(undefined);
var j = 0;
function obsQueue() {
return obs = obs.flatMap(() => {
return Rx.Observable.of(++j);
});
}
obsQueue().subscribe(result => {
console.log(result); // 1
});
obsQueue().subscribe(result => {
console.log(result); // 3
});
obsQueue().subscribe(result => {
console.log(result); // 6
});
// -> 1, 3, 6
每次订阅时,它都会重新执行Observable的历史记录,因为在订阅时,当前的Observable"实际上是一个Observable,它发出多个值,而不是只等到最后一次执行完成的Promise。
flatMap
不是这个用例的答案,而且几乎所有"链都是"和"队列"我在网上找到的答案是关于链接几个Observable,它们是一个整体Observable的一部分,其中flatMap
是正确的答案。
如何使用Observables创建上述Promise队列函数?
对于上下文,此队列函数正在对话服务中使用,该服务指示一次只能显示一个对话框。如果进行多次调用以显示不同的对话框,则它们只按照调用它们的顺序一次显示一个。
答案 0 :(得分:0)
如果你改变:
return obs = obs.flatMap...
使用
return obs.flatMap...
您将看到与promises(1,2,3)相同的输出。
要链接可观察对象,以便在上一个完成之前不执行下一个,请使用the concat
operator
let letters$ = Rx.Observable.from(['a','b','c']);
let numbers$ = Rx.Observable.from([1,2,3]);
let romans$ = Rx.Observable.from(['I','II','III']);
letters$.concat(numbers$).concat(romans$).subscribe(e=>console.log(e));
//or...
Rx.Observable.concat(letters$,numbers$,romans$).subscribe(e=>console.log(e));
// results...
a b c 1 2 3 I II III
答案 1 :(得分:-1)
想出来!可能不如Promise链条那么优雅,我绝对愿意接受清理它的建议。
var trigger = undefined;
function obsQueue() {
if (!trigger || trigger.isStopped) {
trigger = new Rx.Subject();
return createObservable(trigger);
} else {
var lastTrigger = trigger;
var newTrigger = trigger = new Rx.Subject();
return lastTrigger.last().mergeMap(() => {
return createObservable(newTrigger);
});
}
}
var j = 0;
function createObservable(trigger) {
// In my use case, this creates and shows a dialog and returns an
// observable that emits and completes when an option is selected.
// We want to make sure we only create the next dialog when the previous
// one is closed.
console.log('creating');
return new Rx.Observable.of(++j).finally(() => {
trigger.next();
trigger.complete();
});
}
obsQueue().subscribe(result => {
console.log('first', result);
});
obsQueue().subscribe(result => {
console.log('second', result);
});
obsQueue().subscribe(result => {
console.log('third', result);
});
var timer = setTimeout(() => {
obsQueue().subscribe(result => {
console.log('fourth', result);
});
}, 1000);
// Output:
// creating
// first 1
// creating
// second 2
// creating
// third 3
// creating
// fourth 4
我没有试图找出如何按顺序链接它们,而是让每个observable创建自己的触发器,让下一个observable知道何时创建它自己。
如果所有触发器都已完成(setTimeout
,我们稍后再排队),然后队列再次启动。