来自链式承诺的RxJS Observable的执行顺序

时间:2016-08-07 14:26:37

标签: javascript promise rxjs

在AnuglarJS 2应用程序中,我想通过链式承诺制作Observable。由于承诺提供一次性结果,第一步是使用Observable.fromPromise()然后{meta} mapAll()来处理每个complete的{​​{1}}。我在这里发现了有用的问题RxJS: How to have one Observer process multiple Observables?

由于上述问题的公认答案涉及简单事件,我使用fromPromise代替Observable.fromPromise(someComposedPromise)轻松准备了自己的解决方案。不幸的是,虽然一切都适用于简单的单一承诺,但问题出现在承诺由两个承诺组成,因为承诺得到解决的顺序。

为了简单起见,我们假设我们有一些现有的外部Observable.fromEvent(someEvent)(我想使用的是Ionic 2 LocalStorage,其中最简单的变体看起来类似于这个):

DumbCache

然后上述方法是:

class DumbCache {
  cache = {};

  get(key) {
    return new Promise((resolve, reject) => {
      var value = this.cache[key];
      resolve(value);
    });
  }

  set(key, value) {
    return new Promise((resolve, reject) => {
      this.cache[key] = value;
      resolve();
    });
  }
}

现在为以下代码:

class CacheValueObservable {
  private cache: DumbCache;

  constructor(private key: string) {
    this.cache = new DumbCache();
  }

  /*
   * meta observer to handle promises from observables with all results and errors
   * thanks to ReplaySubject(1) current value is available immediately after subscribing 
   */
  private _valueSource$$ = new Rx.ReplaySubject(1);
  private _value$ = this._valueSource$$.mergeAll();

  public value$() { return this._value$; }

  public updateValue(value) {
    this._valueSource$$.next(
      Rx.Observable.fromPromise(
        this.cache.set(this.key, value)
        .then(() => this.cache.get(this.key))
      )
    );
  }
}

结果是:

let cacheValueObservable = new CacheValueObservable("TEST_KEY");
cacheValueObservable.updateValue('VALUE 0');

cacheValueObservable.value$().subscribe(
    val => {
      console.log('val:' + val);
    },
    val => console.log('err', val.stack),
    () => (console.log('complete'))
);

cacheValueObservable.updateValue('VALUE 1');
cacheValueObservable.updateValue('VALUE 2');

console.log('end');
显然,我想实现

starting...
end
val:VALUE 2
val:VALUE 2
val:VALUE 2

此处的完整示例:http://jsbin.com/wiheki/edit?js,console

1 个答案:

答案 0 :(得分:1)

在试图表达要充分描述的问题的同时,我仍然在更好,更好地调查和理解这个问题。重点是第一个承诺this.cache.set(this.key, value)实际上可以立即得到解决,而Observable.fromPromise不能保证所有以下链式承诺的解决顺序。

问题是由于每个链的最后一个承诺仅在状态被最后一个链的第一个承诺(因此VALUE 2)改变之后才被执行。

从代码的角度来看,所有的解决方案看起来都非常简单,但由于两个关键的变化,它并不那么明显:

  • 使用mergeAll代替Observable.defer
  • 将初始承诺执行推迟到Observable.fromPromise阶段
  • 使用mergeAll(1)
  • 限制(或实际禁用)合并承诺的并发性

因此工作解决方案如下所示:

class CacheValueObservable {
  private cache: DumbCache;

  constructor(private key: string) {
    this.cache = new DumbCache();
  }

  /*
   * meta observer to handle promises from observables with all results and errors
   * thanks to ReplaySubject(1) current value is available immediately after subscribing 
   */
  private _valueSource$$ = new Rx.ReplaySubject(1);
  // disable merge concurrency 
  private _value$ = this._valueSource$$.mergeAll(1);

  public value$() { return this._value$; }

  public updateValue(value) {
    this._valueSource$$.next(
      // defer promise resolution to ensure they will be fully resolved
      // one by one thanks to no concurrency in mergeAll
      Rx.Observable.defer(() =>
        this.cache.set(this.key, value)
        .then(() => this.cache.get(this.key))
      )
    );
  }
}

这是实例: http://jsbin.com/bikawo/edit?html,js,console