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

Multiple nested AJAX requests with arrays

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

  1. 得到masterlist.xml.
  2. 解析主列表以获取类别列表 URL 数组。
  3. 得到每个 category.xml.
  4. 解析每个类别列表以获取一组清单 URL。
  5. 获取每个 manifest.xml 并解析数据。

示例结构:

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 中是如何构建的?

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

这里是您如何执行此操作的粗略概述。

// 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 或其他提供 promises .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
    });

当然,如果您不想导入整个第三方 promise 库,您也可以定义自己的 .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;
    });
}