javascript - 使用嵌套的异步请求循环遍历异步请求

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

我有一个场景,我正在调用一个具有分页的 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-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);
    }
}

关于javascript - 使用嵌套的异步请求循环遍历异步请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54904818/

相关文章:

javascript - Browserify、Babel 6、Gulp - 传播运算符上出现意外标记

javascript - 如何将 typescript 类型的字符串转换为字符串数组?

javascript - Modernizr 类不适用于 HTML

javascript - 使用 Transform 的 Z 索引堆叠问题

node.js - nodejs检查文件是否存在,如果不存在,等到存在

javascript - 使用 Javascript/jQuery 在 HTML 中列出 map 数据

javascript - 如何确保外部 JS 代码作为第一个加载

node.js - 安装phonegap时出现错误

javascript - AWS Lambda HTTP POST 请求 (Node.js)

javascript - 通过id查找state中的对象,如果找到对象则执行某些操作,如果未找到对象则执行其他操作