Javascript 同步处理嵌套数组

Javascript 同步处理嵌套数组,javascript,asynchronous,async-await,Javascript,Asynchronous,Async Await,我正在重构一些爬网网页的代码(删除“回调地狱”),并希望在每个请求之间有三秒钟的延迟。以下是请求函数: const getHTML = function(page, i) { return new Promise(function(resolve, reject) { setTimeout(function () { api.makeAPIGetRequest(page).then((html) => { re

我正在重构一些爬网网页的代码(删除“回调地狱”),并希望在每个请求之间有三秒钟的延迟。以下是请求函数:

const getHTML = function(page, i) {
    return new Promise(function(resolve, reject) {
        setTimeout(function () {
            api.makeAPIGetRequest(page).then((html) => {
                resolve(html);
            }).catch((err) => {
                reject(err);
            })
        }, i * 3000);
    });
}
我正在遍历一个对象数组,然后遍历一个数组:

let p = [
    {
        location: 'England',
        pages: [1, 3, 5]
    },
    {
        location: 'Scotland',
        pages: [2, 4, 6]
    }
];
问题是输出是随机的(因为延迟):

应该是:

Page 1 - Loaded
Page 3 - Loaded
Page 5 - Loaded
Page 2 - Loaded
Page 4 - Loaded
Page 6 - Loaded
这是我的密码:

p.map(async (data) => {
    await crawlLocationPages(data);
})

function crawlLocationPages(data) {

    return Promise.all(
        data.pages.map(async (page, i) => {
            await getHTML(page, i).then((html) => { // <-- waits 3 seconds
                console.log('Page ' + page + ' - Loaded' );
            });

        })
    ).then(() => {

    })

};
p.map(异步(数据)=>{
等待爬网定位页面(数据);
})
函数爬行位置页面(数据){
回报你的承诺(
data.pages.map(异步(第页,i)=>{
等待getHTML(第i页),然后((html)=>{//{
})
};
我宁愿保持对象和数组模型不变


非常感谢您的帮助。

这种方法可能不太容易混淆,但只有在每个请求所需时间不超过3秒时才有效

pages=p.flatMap(位置=>location.pages);
page=0;
var interval=setInterval(()=>{
如果(页面===页面长度){
间隔时间;
}
makeAPIGetRequest(页面[page++])。然后((html)=>{
log('Page'+Page+'-Loaded');
}).catch((错误)=>{
控制台错误(err);
});

},3000);
这种方法可能不太容易混淆,但只有在每个请求所需时间不超过3秒时才有效

pages=p.flatMap(位置=>location.pages);
page=0;
var interval=setInterval(()=>{
如果(页面===页面长度){
间隔时间;
}
makeAPIGetRequest(页面[page++])。然后((html)=>{
log('Page'+Page+'-Loaded');
}).catch((错误)=>{
控制台错误(err);
});

},3000);
使用ES6生成器和
产量解决了这个问题

function* crawlGenerator() {
    for (let i = 0; i <= (p.length - 1); i++) {

        yield crawlLocationPages(p[i]);
    }

}

let crawl = crawlGenerator();
crawl.next();

function crawlLocationPages(data) {

    return Promise.all(
        data.pages.map(async (page, i) => {
            await getHTML(page, i).then((html) => { // <-- waits 3 seconds
                console.log('Page ' + page + ' - Loaded' );
            });

        })
    ).then(() => {
        crawl.next();
    })

};
函数*crawlGenerator(){
for(设i=0;i{
等待getHTML(第i页),然后((html)=>{//{
crawl.next();
})
};

此处的更多信息:

使用ES6生成器和
产量解决了此问题

function* crawlGenerator() {
    for (let i = 0; i <= (p.length - 1); i++) {

        yield crawlLocationPages(p[i]);
    }

}

let crawl = crawlGenerator();
crawl.next();

function crawlLocationPages(data) {

    return Promise.all(
        data.pages.map(async (page, i) => {
            await getHTML(page, i).then((html) => { // <-- waits 3 seconds
                console.log('Page ' + page + ' - Loaded' );
            });

        })
    ).then(() => {
        crawl.next();
    })

};
函数*crawlGenerator(){
for(设i=0;i{
等待getHTML(第i页),然后((html)=>{//{
crawl.next();
})
};

这里有更多信息:

await
.map
.forEach
中不起作用,但它在
中对
循环起作用。当然,它必须在
异步
函数中

const run = async () => {
    for(let data of p){
        await crawlLocationPages(data);
    }
}

const crawlLocationPages = async data => {
    for(let page of data.pages){
        const html = await getHTML(page);
        console.log('Page ' + page + ' - Loaded - HTML = ', html );
        await pause();
    }
}

const pause = () => new Promise( (resolve, reject) => setTimeout(resolve, 3000) );

run()

await
.map
.forEach
内部不起作用,但它在
内部对
循环起作用。当然,它必须在
异步
函数内部

const run = async () => {
    for(let data of p){
        await crawlLocationPages(data);
    }
}

const crawlLocationPages = async data => {
    for(let page of data.pages){
        const html = await getHTML(page);
        console.log('Page ' + page + ' - Loaded - HTML = ', html );
        await pause();
    }
}

const pause = () => new Promise( (resolve, reject) => setTimeout(resolve, 3000) );

run()

您好,您的问题中没有包含_delay的值,我假设它是
1000
ms,对吗?3000ms-我希望每个页面请求之间有3秒的延迟。您可以将所有API响应存储在一个数组中,并仅在所有请求完成后打印。或者,您可以在响应到来时打印,只需维护一个包含所有响应的数组onses已打印,打印前请检查。如果之前的响应尚未打印,请将响应放入对象中,稍后再打印。您好,您的问题中没有包含_delay的值,我假设它是
1000
ms,对吗?3000ms?我希望每个页面请求之间有3秒的延迟。您可以存储所有API请求在数组中进行PONSE,并在所有请求完成后才打印。或者,您可以在响应出现时打印,只需维护一个包含所有已打印响应的数组,并在打印前检查检查。如果之前的响应尚未打印,请将响应放入对象中,稍后再打印。这是一个不错的解决方案。我使用ES6生成器是因为他
getHTML
函数目前不在我的范围内。解决方案不错。我使用ES6生成器,因为
getHTML
函数目前不在我的范围内。