如何在JS的setInterval内部等待? [英] How to await inside setInterval in JS?
问题描述
我有一个看起来像这样的代码段:
I have a code segment that looks like this:
async function autoScroll(page, maxDate = null) {
await page.evaluate(async () => {
await new Promise(async (resolve, reject) => {
try {
const scrollHeight = document.body.scrollHeight;
let lastScrollTop = 0;
const interval = setInterval(async () => {
window.scrollBy(0, scrollHeight);
const scrollTop = document.documentElement.scrollTop;
let lastDate = null;
if (maxDate) {
const html = new XMLSerializer().serializeToString(document.doctype) + document.documentElement.outerHTML;
await extractDate(html).then((date) => {
lastDate = date;
});
}
if (scrollTop === lastScrollTop ||
(maxDate && lastDate && maxDate.getTime() >= lastDate.getTime())) {
clearInterval(interval);
resolve();
} else {
lastScrollTop = scrollTop;
}
}, 2000);
} catch (err) {
console.error(err);
reject(err.toString());
}
});
});
}
extractDate
方法的格式如下:
function extractDate(html) {
return new Promise((resolve, reject) => {
// Rest removed for brevity.
resolve(result);
});
}
现在的问题是,我的代码不断滚动,但它不等待 setInterval
中的其他内容完成,因为它每2秒滚动一次,但通常 extractDate
函数应该花费超过2秒的时间,因此我实际上想等待 setInterval
中的所有操作完成,然后再调用新间隔.
Now the problem is that, my code keeps scrolling, but it doesn't wait for the other stuff inside setInterval
to finish, as it keeps scrolling every 2 seconds, but normally extractDate
function should take longer than 2 seconds, so I actually want to await for everything inside setInterval
to finish before making the call to the new interval.
由于内容的异步性质,因此我没有设法对console.log 进行操作,因此请查看代码的行为.
Because of the async nature of stuff, I didn't manage to console.log
stuff so see the behavior of the code.
那么,如何在进行下一次间隔调用之前确保 setInterval
中的所有内容都已完成?
So, how can I make sure that everything inside setInterval
finishes before making the next interval call?
此使用 setTimeout
的解决方案只滚动一次,并向操纵up发送未处理的承诺拒绝错误.
This solution using setTimeout
scrolls just once and throws unhandled promise rejection error with puppeteer.
async function autoScroll(page, maxDate = null) {
await page.evaluate(async () => {
await new Promise(async (resolve, reject) => {
try {
const scrollHeight = document.body.scrollHeight;
let lastScrollTop = 0;
const interval = async function() {
window.scrollBy(0, scrollHeight);
const scrollTop = document.documentElement.scrollTop;
let lastDate = null;
if (maxDate) {
const html = new XMLSerializer().serializeToString(document.doctype) + document.documentElement.outerHTML;
await extractDate(html).then((date) => {
lastDate = date;
});
}
if (scrollTop === lastScrollTop ||
(maxDate && lastDate && maxDate.getTime() >= lastDate.getTime())) {
resolve();
} else {
lastScrollTop = scrollTop;
setTimeout(interval, 2000);
}
}
setTimeout(interval, 2000);
} catch (err) {
console.error(err);
reject(err.toString());
}
});
});
}
推荐答案
将interval函数转换为递归 setTimeout
函数,这样您可以为函数完成后的下一次迭代.
Turn the interval function into a recursive setTimeout
function instead, that way you can initialize a timeout for the next iteration once the function has finished.
async function doScroll() {
window.scrollBy(0, scrollHeight);
const scrollTop = document.documentElement.scrollTop;
let lastDate = null;
if (maxDate) {
const html = new XMLSerializer().serializeToString(document.doctype) + document.documentElement.outerHTML;
await extractDate(html).then((date) => {
lastDate = date;
});
}
if (scrollTop === lastScrollTop ||
(maxDate && lastDate && maxDate.getTime() >= lastDate.getTime())) {
// No need to `clearInterval`:
resolve();
} else {
lastScrollTop = scrollTop;
// Recursive setTimeout:
setTimeout(doScroll, 2000); // <------------------
}
}
setTimeout(doScroll, 2000);
这篇关于如何在JS的setInterval内部等待?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!