将可观察的反应合并为一个

时间:2017-12-22 23:01:58

标签: javascript react-native promise redux-observable

如何从多个observable获取对象响应?

我的史诗喜欢这个:

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({ couriers, items, airports }),但首先我需要等待所有3个承诺完成并以某种方式将对象组合作为响应。

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

2 个答案:

答案 0 :(得分:2)

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

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来等待多个Promises的结果。 Promise.all返回一个Promise,它解析为一个数组,其中每个元素都是输入数组中相应项的结果。我们将这个数组转换为一个对象并传递它。

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

&#13;
&#13;
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);
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

我脑子里有两个解决方案,你可以试试它们是否符合你的情况:

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));
        });
    });
}

$a = Get-ChildItem C:\tejasoft -recurse | Where-Object {$_.PSIsContainer -eq $True -and ($_.GetDirectories().Count -eq 0)}
$path = $a | Where-Object {$_.GetFiles().Count -eq 0} | foreach {$_.FullName}
$a | Where-Object {$_.GetFiles().Count -eq 0} | foreach {$_.FullName}|ForEach-Object -Process {New-Item -Path $path -Name ".keep" -Value "Test Value" -ItemType File }