带有数组的多个嵌套AJAX请求

时间:2017-11-08 14:31:57

标签: javascript ajax axios

我正在使用Axios / promises来发出AJAX请求,但结构有点令人困惑。基本上我希望这种情况发生:

  1. 获取masterlist.xml
  2. 解析主列表以获取类别列表URL数组。
  3. 获取每个category.xml
  4. 解析每个类别列表以获取一系列清单URL。
  5. 获取每个manifest.xml并解析数据。
  6. 示例结构:

    masterlist.xml

    <master>
      <category>action</category>
      <category>romance</category>
    </master>
    

    类别XML(例如action.xml和romance.xml)

    <manifestUrls>
      <manifest>foo/bar/manifest.xml</manifest>
      <manifest>alice/bob/manifest.xml</manifest>
      <manifest>hello/world/manifest.xml</manifest>
    </manifestUrls>
    

    显示XML

    <manifest>
      <data>Blah blah blah</data>
    <manifest>
    

    我对如何将此结构化为具有then的Axios请求感到困惑。我希望有三个函数getMaster()getCategory(url)getManifest(url)最好是独立的(例如getMaster不必直接调用getCategory ),但似乎可能是必要的。

    如何在Axios中构建这个结构?

1 个答案:

答案 0 :(得分:3)

承诺的主要好处之一是它们可以让您轻松避免方法之间的相互依赖。

以下是如何做到这一点的大致概述。

// put it all together
getMaster()
    .then(parseMaster)
    .then(function (categories) {
        return Promise.all(categories.map(getAndParseCategory));
    })
    .then(flatten)  // the previous then() resolves to an array-of-arrays
    .then(function (manifestUrls) {
        return Promise.all(manifestUrls.map(getManifest));
    })
    .then(function (manifests) {
        // manifests is an array of all manifests
    });


// Examples of what each of the functions used above would do
function getMaster() {
    return axios.get('masterUrl')
        .then(function (response) { return response.data; });
}

function parseMaster(masterContent) {
    // parse and return an array of categories
}

function getCategory(name) {
    var url = // ... build the URL based on the name

    return axios.get(url)
        .then(function (response) { return response.data; });
}

function parseCategory(categoryContent) {
    // parse and return an array of URLs synchronously for one category
}

function getAndParseCategory(name) {
    return getCategory(name).then(parseCategory);
}

function getManifest(url) {
    return axios.get(url)
        .then(function (response) { return response.data; });
}

function flatten(arrayOfArrays) {
    return [].concat.apply([], arrayOfArrays);
}

如果您正在使用Bluebird或其他为承诺提供.map()方法的东西,那么您可以稍微整理一下这个管道:

// using Promise.resolve() at the beginning to ensure 
// the chain is based of the desired kind of promise
Promise.resolve()
    .then(getMaster)
    .then(parseMaster)
    .map(getCategory)
    .map(parseCategory)
    .then(flatten)       // previous line resolves to an array-of-arrays
    .map(getManifest)
    .then(function (manifests) {
        // manifests is an array of all manifests
    });

当然,如果您不想导入整个第三方承诺库,也可以定义自己的.map方法:

if (!Promise.prototype.map) {
    Promise.prototype.map = function (func) {
        return this.then(function (result) {
            return Promise.all(result.map(func));
        });
    };
}

修改:在下面的评论中回答您的问题。如果您想传递类别文本以便它可以包含在清单URL中,我认为一种干净的方法是将其包含在getCategory()返回的数据中,以便parseCategory可以利用它。其他一切都可以保持不变。

示例:

function getCategory(name) {
    var url = // ... build the URL based on the name

    return axios.get(url)
        .then(function (response) { 
            return {
                name: name,
                data: response.data 
            };
        });
}

function parseCategory(categoryContent) {
    var urls = // parse URLs from categoryContent.data

    return urls.map(function (url) {
        return categoryContent.name + '/' + url;
    });
}