将可观察到的响应合并为一个

Combine observable responses into one

如何从多个可观察对象获得 object 响应?

我的史诗是这样的:

export function metaDataEpic(action$: ActionsObservable<metaDataActions>) { 
    return action$.ofType(META_DATA_REQUEST)
      .mergeMap((action: metaDataActions) => {
        const { language } = action;
        return Observable.merge(
          Observable.fromPromise(couriersApi().then(r => r.json())),
          Observable.fromPromise(itemCategoriesApi({ language }).then(r => r.json())),
          Observable.fromPromise(airportsApi().then(r => r.json())))
          .flatMap(res => {
            console.log(res);
            return Observable.of(getMetaDataSuccess({}))
          });
      });
}

我需要的是将 getMetaDataSuccess()courierApi()itemCategoriesApi()airportsApi() 的响应传递给函数 getMetaDataSuccess() [=15] =] 但首先我需要等待所有 3 个承诺完成并以某种方式组合成 object 作为响应。

我的代码现在所做的是打印来自 API 的响应,从而调用 getMetaDataSuccess 3 次。 enter code here

听起来你想要这样的东西。

export function metaDataEpic(action$: ActionsObservable<metaDataActions>) { 
    return action$.ofType(META_DATA_REQUEST)
      .flatMap(({language}) => Promise.all([
            couriersApi(),
            itemCategoriesApi({language}),
            airportsApi()
          ].map(p => p.then(r => r.json()))
        )
        .then(([couriers, items, airports]) => ({couriers, items, airports}))
      )
      .do(console.log)
      .map(getMetaDataSuccess);
}

flatMap aka mergeMap 可以直接对 Promise 和 Arraylike 值进行操作。这里我们使用 Promise.all 来等待多个 Promise 的结果。 Promise.all returns 解析为数组的 Promise,其中每个元素都是输入数组中相应项的结果。我们将这个数组转换成一个对象并传递给它。

这里是用虚拟数据证明它有效的。

function couriersApi() {
  return Promise.resolve({
    json: () => [{
      name: 'x',
      id: 1
    }, {
      name: 'y',
      id: 2
    }]
  });
}

function airportsApi() {
  return Promise.resolve({
    json: () => [{
      name: 'ORF',
      id: 1
    }, {
      name: 'JFK',
      id: 2
    }]
  });
}

function itemCategoriesApi({language}) {
  return Promise.resolve({
    json: () => [{
        name: 'a',
        language: 'German'
      },
      {
        name: 'b',
        language: 'English'
      },
    ].filter(c => c.language === language)
  });
}
const META_DATA_REQUEST = undefined;
const action$ = {
  ofType: () => Rx.Observable.of({
    language: 'English'
  })
};

metaDataEpic(action$)
  .subscribe();

function getMetaDataSuccess(o) {
  console.log(o.couriers);
  console.log(o.items);
  console.log(o.airports);
}

function metaDataEpic(action$) {
  return action$.ofType(META_DATA_REQUEST)
    .flatMap(({
        language
      }) => Promise.all([
        couriersApi(),
        itemCategoriesApi({
          language
        }),
        airportsApi()
      ].map(p => p.then(r => r.json())))
      .then(([couriers, items, airports]) => ({
        couriers,
        items,
        airports
      }))
    )
    .do(console.log)
    .map(getMetaDataSuccess);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script>

我有两个解决方案,你可以试试它们是否适用于你的情况:

export function metaDataEpic(action$: ActionsObservable<metaDataActions>) {
    return action$
    .ofType(META_DATA_REQUEST)
    .mergeMap((action: metaDataActions) => {
        const {language} = action;

        const requestObservable = Observable.zip(
            Observable.fromPromise(couriersApi().then(r => r.json())),
            Observable.fromPromise(
                itemCategoriesApi({language}).then(r => r.json())
            ),
            Observable.fromPromise(airportsApi().then(r => r.json())),
            (couriers, items, airports) => {
                return Observable.of(getMetaDataSuccess({ couriers, items, airports })) ).map(response => response.value)
            }
        ).catch(e => {
            return Observable.of(getMetaDataFail(e));
        });

        return requestObservable;
    });
}

export function metaDataEpic(action$: ActionsObservable<metaDataActions>) {
    return action$
    .ofType(META_DATA_REQUEST)
    .mergeMap((action: metaDataActions) => {
        const {language} = action;

        Promise.all(
            [couriersApi(), itemCategoriesApi({language}), airportsApi()].map(p =>
                p.then(r => r.json())
            )
        )
        .then(([couriers, items, airports]) => {
            return Observable.of(getMetaDataSuccess({couriers, items, airports}));
        })
        .catch(e => {
            return Observable.of(getMetaDataFail(e));
        });
    });
}