【问题标题】:Loop through async requests with nested async requests循环使用嵌套异步请求的异步请求
【发布时间】:2019-07-21 03:16:20
【问题描述】:

我有一个场景,我正在调用具有分页功能的 API。 我想做的是以下内容,一次一页。

  1. 调用 API 页面 1
  2. 对于响应中的每个项目,调用 Promise 以获取更多数据并存储在数组中
  3. 将数组发送到 API
  4. 重复直到所有页面都完成

我目前拥有以下内容,但我认为我可能使这过于复杂,尽管不确定如何进行。

export const importData = async() {
    const pSize = 15;
    const response = await getItems(pSize, 1);
    const noPage = Math.ceil(response.totalMerchandiseCount/pSize);

    for (let i = 1; i < noPage; i++) {
        const items = [];
        const data = await getItems(pSize, i);

        await async.each(data.merchandiseList, async(i, cb) => {
            const imageURL = await getImageURL(i.id, i.type);
            items.push({
                id: i.id,
                imageURL: imageURL,
            });
            cb();
        }, async() => {
            return await api.mockable('sync', items);
        });
    }
}

export const getImageURL = async(id, type) => {
    let url = `https://example.com/${id}`;

    return axios.get(url)
        .then((response) => {
            const $ = cheerio.load(response.data);

            // do stuff to get imageUrl

            return image;
        })
        .catch((e) => {
            console.log(e);
            return null;
        })
};

我目前遇到的问题是,它似乎要等到所有页面都完成后才能调用 api.mockable。此时项目也是空的。

任何人都可以提出一种方法来使它更整洁并帮助我让它工作吗?

【问题讨论】:

  • 你是要一个接一个地做,还是并行做?
  • 旁注 - 这可能比你想要的少一个:for (let i = 1; i &lt; noPage; i++) {。通常它是“从 0 开始并使用
  • 您在某些地方使用async 作为标识符(例如async.each)。是Axios的吗?还是别的什么?
  • @T.J.Crowder 页面应该一个接一个。获取第一页,获取额外数据,发送数据,等待响应,下一页。 async.each 来自异步库,尽管我再次不确定我是否需要它或者它是否使事情变得复杂。

标签: javascript node.js ecmascript-6 async-await


【解决方案1】:

如果这都是串行的,那么您可以使用 for-of 循环:

export const importData = async() {
    const pSize = 15;
    const response = await getItems(pSize, 1);
    const noPage = Math.ceil(response.totalMerchandiseCount/pSize);

    for (let i = 1; i < noPage; i++) { // Are you sure this shouldn't be <=?
        const items = [];
        const data = await getItems(pSize, i);

        for (const {id, type} of data.merchandiseList) {
            const imageURL = await getImageURL(id, type);
            items.push({id, imageURL});
        }
        await api.mockable('sync', items);
    }
}

我还在其中添加了一些解构和速记属性。 :-)

如果只是串行的页面,但您可以并行获取项目,则可以将项目上的for-of替换为mapPromise.all

export const importData = async() {
    const pSize = 15;
    const response = await getItems(pSize, 1);
    const noPage = Math.ceil(response.totalMerchandiseCount/pSize);

    for (let i = 1; i < noPage; i++) { // Are you sure this shouldn't be <=?
        const data = await getItems(pSize, i);
        const items = await Promise.all(data.merchandiseList.map(async ({id, type}) => {
            const imageURL = await getImageURL(id, type);
            return {id, imageURL};
        }));
        await api.mockable('sync', items);
    }
}

async 函数调用到map 可以稍微作为非async 函数更有效:

export const importData = async() {
    const pSize = 15;
    const response = await getItems(pSize, 1);
    const noPage = Math.ceil(response.totalMerchandiseCount/pSize);

    for (let i = 1; i < noPage; i++) {
        const data = await getItems(pSize, i);
        const items = await Promise.all(data.merchandiseList.map(({id, type}) =>
            getImageURL(id, type).then(imageURL => ({id, imageURL}))
        ));
        await api.mockable('sync', items);
    }
}

【讨论】:

  • (如果您在最后一个代码块中看到i.idi.type——或者其中任何一个,真的——点击刷新。编辑错误。)
  • 完美,连续页面和并行项目工作。谢谢:)
猜你喜欢
  • 2017-11-22
  • 2016-06-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-24
  • 2017-11-15
  • 2017-03-17
  • 1970-01-01
相关资源
最近更新 更多