如何在JS中映射对象数组并获取每个对象的网络数据?

时间:2018-08-14 12:39:42

标签: javascript axios es6-promise

我正在使用React Native开发应用程序。我必须从URL提取类别的数据数组,然后对于每个类别,我必须从其各自的URL提取资产。

我的数据以以下格式存储:

来自mainURL

{
  "id": 1,
  "name": "Home",
  "type": "",
  "url": "",
  "subCategories": [
    {
      "id": 92,
      "name": "Documentary",
      "type": "JTV_LEAF",
      "url": "yyy",
    }
  ]
}

从每个类别URL,

[
  {
    "id": "1",
    "title": "Inception",
    "type": "vod"
  }
]

如何使用mapreduceaxios获取每个类别的数据?


这是我到目前为止所写的。最后我得到undefined

export const fetchNavigationFeed = (navUrl, subId) => {
  return dispatch => {
    const url = navUrl
      .replace("__JTV__SUBSCRIBER__ID__", subId);
    dispatch({ type:FETCH_NAVIGATION_FEED });
    return axios.get(url)
      .then(response => {
        let categories = [];
        for (var i = 0; i < response.data.subCategories.length; i++) {
            var cat = response.data.subCategories[i];
            var category = new Category(cat);
            categories.push(category);
        }
        console.log(categories);
        let promises = [];
        categories.map(category => {
          let request = axios.get(category.url)
            .then(assetsJson => {
              let assets = [];
              for (var i = 0; i < assetsJson.data.length; i++) {
                  var ass = assetsJson.data[i];
                  var asset = new Asset(ass);
                  assets.push(asset);
              }
              category.assets = assets;
            });
          promises.push(request);
        });
        axios.all(promises)
          .then(axios.spread(...args) => {
            console.log(args);
          });
        return categories;
      })
      .then(categories => {
        // console.log(categories);
        dispatch({ type:FETCH_NAVIGATION_FEED_SUCCESS, payload:categories });
      });
  }
}

2 个答案:

答案 0 :(得分:4)

这是一个有效的示例,并进行了jest测试:


code.js

import axios from 'axios';

export const FETCH_NAVIGATION_FEED = 'FETCH_NAVIGATION_FEED';
export const FETCH_NAVIGATION_FEED_SUCCESS = 'FETCH_NAVIGATION_FEED_SUCCESS';

class Category {
  constructor(json) {
    this.id = json.id;
    this.name = json.name;
    this.url = json.url;
  }
}

class Asset {
  constructor(json) {
    this.id = json.id;
    this.title = json.title;
  }
}

export const fetchNavigationFeed = (navUrl, subId) => {
  return async (dispatch) => {
    dispatch({ type: FETCH_NAVIGATION_FEED });

    const url = navUrl
      .replace('__JTV__SUBSCRIBER__ID__', subId);
    const response = await axios.get(url);
    const categories = [];
    const promises = [];
    response.data.subCategories.forEach((subCategory) => {
      const category = new Category(subCategory);
      categories.push(category);
      const promise = axios.get(category.url).then((subResponse) => {
        category.assets = [];
        subResponse.data.forEach((asset) => {
          category.assets.push(new Asset(asset));
        });
      });
      promises.push(promise);
    });
    // wait for all the promises simultaneously
    await Promise.all(promises);

    dispatch({ type: FETCH_NAVIGATION_FEED_SUCCESS, payload: categories });
  }
}

code.test.js

import axios from 'axios';
import {
  fetchNavigationFeed,
  FETCH_NAVIGATION_FEED,
  FETCH_NAVIGATION_FEED_SUCCESS
} from './code';

const getMock = jest.spyOn(axios, 'get');
getMock.mockImplementation((url) => {
  switch (url) {
    case 'mainUrl-mySubId':
      return Promise.resolve({
        data: {
          "id": 1,
          "name": "home",
          "subCategories": [
            {
              "id": 2,
              "name": "sub1",
              "url": "sub1Url",
            },
            {
              "id": 3,
              "name": "sub2",
              "url": "sub2Url",
            }
          ]
        }
      });
    case 'sub1Url':
      return Promise.resolve({
        data: [
          {
            "id": 4,
            "title": "asset1"
          },
          {
            "id": 5,
            "title": "asset2"
          }
        ]
      });
    case 'sub2Url':
      return Promise.resolve({
        data: [
          {
            "id": 6,
            "title": "asset3"
          },
          {
            "id": 7,
            "title": "asset4"
          }
        ]
      });
  }
});


test('getData', async () => {
  const asyncDispatch = fetchNavigationFeed('mainUrl-__JTV__SUBSCRIBER__ID__', 'mySubId');
  const dispatch = jest.fn();
  await asyncDispatch(dispatch);
  expect(dispatch).toHaveBeenCalledTimes(2);
  const firstCallArgs = dispatch.mock.calls[0];
  expect(firstCallArgs).toEqual([{
    type: FETCH_NAVIGATION_FEED
  }]);
  const secondCallArgs = dispatch.mock.calls[1];
  expect(secondCallArgs).toEqual([{
    type: FETCH_NAVIGATION_FEED_SUCCESS,
    payload: [
      {
        id: 2,
        name: 'sub1',
        url: 'sub1Url',
        assets: [
          {
            "id": 4,
            "title": "asset1"
          },
          {
            "id": 5,
            "title": "asset2"
          }
        ]
      },
      {
        id: 3,
        name: 'sub2',
        url: 'sub2Url',
        assets: [
          {
            "id": 6,
            "title": "asset3"
          },
          {
            "id": 7,
            "title": "asset4"
          }
        ]
      }
    ]
  }]);
});

请注意:您可以使用axios.all(),但根据this thread,它仍然可以使用Promise.all()

答案 1 :(得分:-1)

您可以执行以下操作:

fetch(url)
 .then((response) => response.json())
 .then(async (data) => {
    const categories = data.subCategories
             .map(category => new Category(category.id, category.name, category.type, category.url))

    for(category of categories) {
       let assets = await fetch(category.url).then(rsp => rsp.json())
       assets = assets.map(asset => Asset(assets.id, assets.title, assets.type, ass.thumbnail));
       category.assets = assets;
    }

    return categories
 }).then(categoriesWithAssets => {/*done*/})