我有一个如下代码段:
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
的此解决方案仅滚动一次,并向操纵up发送未处理的承诺拒绝错误。
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());
}
});
});
}
答案 0 :(得分:4)
使用以下代码:
setInterval(async () => {
await fetch("https://www.google.com/")
}, 100);
答案 1 :(得分:2)
我通常选择此解决方案。我认为它更干净:
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
函数将返回一个承诺。您可以等待它停止循环,也可以丢弃它。
答案 2 :(得分:1)
将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);
答案 3 :(得分:1)
将时间间隔改为一个函数,并使用setTimeout将以后的函数调用排队。
const interval = async function () { // instead of setInterval
然后使用setTimeout函数在将来的队列中排队:
setTimeout(interval, 2000);
答案 4 :(得分:0)
如果某人想要更新的解决方案,则可以使用react-timeout,当卸载包装的组件时,该超时会自动取消所有延迟计时器。
更多信息
https://www.npmjs.com/package/react-timeout
npm i react-timeout
使用await时,您可以执行以下操作
handleClick = async() => {
try {
await this.props.getListAction().then(()=>{
this.timeOut = this.props.setTimeOut(this.handleClick, 10000);
});
} catch(err) {
clearTimeout(this.timeOut);
}
}
答案 5 :(得分:0)
在将异步函数用作setInterval
或setTimeout
的参数时,请确保将所有可能引发错误的操作包装在try / catch中,以避免未处理的错误,以及在Node上。 js,请勿调用process.exit
,因为它会抢占事件循环,而无需考虑计时器。在Async, Promises, and Timers in Node.js中有更多详细信息。