如何在 JavaScript 中开始 "infinite" for 循环的下一次迭代之前等到承诺完成

How to wait until a promise is completed before starting the next iteration of an "infinite" for loop in JavaScript

我想弄清楚如何在 for 循环中开始下一次迭代之前等待承诺得到解决。有人建议我使用 setInterval() 函数而不是 for 循环,如果你能猜出 promise 解决所需的时间,这很好,但显然并不理想。

const puppeteer = require('puppeteer-extra')
const StealPlugin = require('puppeteer-extra-plugin-stealth')

puppeteer.use(StealPlugin())
let arrayOfUrls = [
    "https://google.com",
    "https://facebook.com",
    "https://youtube.com",
];

let initialIndex = 0;
let finalIndex = 0;

async function scraper(url) {
    const browser = await puppeteer.launch({headless: false});
    const page = await browser.newPage();
    await page.goto(url);
    await page.screenshot({path: 'example' + initialIndex.toString() + '.png'});
    await console.log(url + "  screenshot complete!")
    await browser.close();
}

const interval = setInterval(() => {
    if (initialIndex < arrayOfUrls.length) {
        scraper(arrayOfUrls[initialIndex]);
        initialIndex += 1;
    } else {
        clearInterval(interval);
        console.log("All complete!")
        loopy()
    }
}, 300)

function loopy() {
    setInterval(() => {
        if (finalIndex === arrayOfUrls.length) {
            finalIndex = 0;
        }
        scraper(arrayOfUrls[finalIndex]);
        finalIndex += 1;
    }, 300)
}

上面的代码目前只是实验性的,但我最终想要实现的是使用文本文件中的 URLs 发出一系列 API 请求,然后创建一个数组每个 URL 包含一个对象。这是我代码中的const interval = setInterval(() => {

然后我希望能够定期再次检查每个请求并检查 API 请求中是否有更改,并无限期地执行此操作。这是我实验代码中的 loopy() 函数。如果有我想给自己发个通知

如果我将 setInterval() 的时间设置为 5000 毫秒之类的高值,我当前的实现工作正常,但如果它是 300 毫秒之类的低值,那么承诺无法足够快地完成,我最终得到了这个错误:

(node:9652) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 exit listeners added to [process]. Use emitter.setMaxListeners() to increase limit

实现此类程序逻辑的最佳方式是什么?


编辑:

根据 WSC 评论中的想法,我尝试了以下方法,它似乎有效。

const puppeteer = require('puppeteer-extra')
const StealPlugin = require('puppeteer-extra-plugin-stealth')

puppeteer.use(StealPlugin())
let arrayOfUrls = [
    "https://google.com",
    "https://facebook.com",
    "https://youtube.com",
];

let initialIndex = 0;
let finalIndex = 0;

async function scraper(url) {
    const browser = await puppeteer.launch({headless: false});
    const page = await browser.newPage();
    await page.waitFor(5000)
    await page.goto(url);
    await page.screenshot({path: 'example' + initialIndex.toString() + '.png'});
    await console.log(url + "  screenshot complete!")
    await browser.close();
}

async function initialScrape() {
    if (initialIndex < arrayOfUrls.length) {
        await scraper(arrayOfUrls[initialIndex]);
        initialIndex += 1;
        initialScrape()
    } else {
        console.log("All complete!")
        loopy()
    }
}


async function loopy() {
    if (finalIndex === arrayOfUrls.length) {
        finalIndex = 0;
    }
    await scraper(arrayOfUrls[finalIndex]);
    finalIndex += 1;
    loopy()
}

initialScrape()

我已经将人为延迟实现到 scraper() 函数中,而不是 await page.waitFor(5000) 的形式。但是,对于我要实现的程序,我不完全确定是否推荐使用此特定实现。

async/await 语法适用于循环。您不需要采用递归方法。

async function main() {
    for (let initialIndex=0; initialIndex<arrayOfUrls.length; initialIndex++) {
        await scraper(arrayOfUrls[initialIndex]);
    }
    console.log("All complete!");
    while (true) {
        for (let finalIndex=0; finalIndex<arrayOfUrls.length; finalIndex++) {
            await scraper(arrayOfUrls[finalIndex]);
        }
    }
}
main().catch(console.error);

或者使用 for … of 循环更容易:

async function main() {
    for (const url of arrayOfUrls) {
        await scraper(url);
    }
    console.log("All complete!");
    while (true) {
        for (const url of arrayOfUrls) {
            await scraper(url);
        }
    }
}
main().catch(console.error);

顺便说一句,为了性能,我建议只调用 puppeteer.launch({headless: false}); 一次,然后使用相同的浏览器实例进行所有屏幕截图。