我有一个代码段,看起来像这样:
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
内部的所有内容完成后,才调用新的时间间隔。
由于东西的异步性质,我没有设法console.log
东西,所以可以看到代码的行为。
那么,在进行下一次间隔调用之前,如何确保setInterval
中的所有内容都完成了呢?
编辑:
这个解决方案使用setTimeout
只滚动一次,并抛出未处理的promise rejection错误。
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());
}
});
});
}
发布于 2018-08-14 04:46:31
相反,将interval函数转换为递归setTimeout
函数,这样一旦函数完成,您就可以为下一次迭代初始化超时。
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);
发布于 2018-12-26 21:18:26
使用以下代码:
setInterval(async () => {
await fetch("https://www.google.com/")
}, 100);
发布于 2019-08-28 02:24:15
我通常选择这种解决方案。我认为它更干净:
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
async function loop() {
while (/* condition */) {
/* code to wait on goes here (sync or async) */
await delay(100)
}
}
您的loop
函数将返回一个promise。您可以等待它停止循环,也可以丢弃它。
https://stackoverflow.com/questions/51830200
复制相似问题