如何在 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});
一次,然后使用相同的浏览器实例进行所有屏幕截图。
我想弄清楚如何在 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});
一次,然后使用相同的浏览器实例进行所有屏幕截图。