Javascript 在JS中如何在setInterval内等待?
我有一个代码段如下所示:Javascript 在JS中如何在setInterval内等待?,javascript,asynchronous,promise,async-await,puppeteer,Javascript,Asynchronous,Promise,Async Await,Puppeteer,我有一个代码段如下所示: async function autoScroll(page, maxDate = null) { await page.evaluate(async () => { await new Promise(async (resolve, reject) => { try { const scrollHeight = document.body.scrollHeight; let las
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
中的所有内容完成,然后再调用新的interval
由于stuff的异步特性,我没有设法console.log
stuff,因此无法查看代码的行为
那么,在进行下一次间隔调用之前,如何确保setInterval
中的所有内容都已完成
编辑:
此解决方案使用setTimeout
仅滚动一次,并使用Puppeter抛出未处理的承诺拒绝错误
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
函数,这样,一旦函数完成,就可以为下一次迭代初始化超时
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);
异步函数doscorl(){
scrollBy(0,scrollHeight);
const scrollTop=document.documentElement.scrollTop;
让lastDate=null;
如果(maxDate){
const html=new XMLSerializer().serializeToString(document.doctype)+document.documentElement.outerHTML;
等待提取日期(html)。然后((日期)=>{
lastDate=日期;
});
}
如果(scrollTop==lastScrollTop||
(maxDate&&lastDate&&maxDate.getTime()>=lastDate.getTime()){
//不需要“清除间隔”:
解决();
}否则{
lastScrollTop=scrollTop;
//递归设置超时:
setTimeout(Doscorl,2000);//将间隔改为函数,并使用setTimeout对未来的函数调用进行排队
const interval = async function () { // instead of setInterval
然后使用setTimeout函数将未来的呼叫排队:
setTimeout(interval, 2000);
小提琴示例:使用以下代码:
setInterval(async () => {
await fetch("https://www.google.com/")
}, 100);
如果有人想要一个更新的解决方案,有一个react timeout,它会在卸载包装好的组件时自动取消任何延迟的计时器 更多信息
https://www.npmjs.com/package/react-timeout
npm i react-timeout
在使用wait时,您可以执行以下操作
handleClick = async() => {
try {
await this.props.getListAction().then(()=>{
this.timeOut = this.props.setTimeOut(this.handleClick, 10000);
});
} catch(err) {
clearTimeout(this.timeOut);
}
}
我通常选择这种解决方案。我认为它更干净:
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)
}
}
您的
循环
函数将返回一个承诺。您可以等待它停止循环,也可以放弃它。当使用异步函数作为setInterval
或setTimeout
的参数时,请确保在try/catch中包装任何可能引发错误的操作,以避免未处理的错误,并且在Node.js上,不要执行以下操作:ll进程。退出
,因为它将先占事件循环,而不考虑计时器。更多详细信息,请参见。您将所有这些都放在try
块中-其他所有内容都是相同的请用您的解决方案检查我编辑的代码。我尝试过,但使用这种方法,它只会滚动一次。无论我是否注释掉e包含等待调用的if语句。以前它一直滚动,直到满足if条件。这个resolve()调用是什么?它没有在块中定义。另外,它不应该是scroll()吗而不是滚动?@NirO。这就是try
块中的代码应该是什么。resolve
在wait new Promise(异步(解析,拒绝)=>{
拒绝中的错误是什么?@aanken它只滚动一次,然后在一段时间后抛出error:protocol error(Runtime.callfunction):Promise已收集
。堆栈跟踪指向一些木偶程序函数。请尝试将interval函数移动到父Promise函数的顶部,并将Try-catch块移动到interval内。在Promise行,尝试返回Promise并从Promise函数中删除async关键字。您是否可以将其作为答案写入此处。Thank你!我一直在寻找这个解决方案(很长时间)当心setInterval会收到一个它不理解的承诺,没有人问过Reacts这是绝对平滑的。我正在将我的调用从mssqlserver转换到node,这解决了其他人发布的函数无法解释的逻辑步骤:在启动任何延迟之前完全完成语句。这很漂亮