首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在JS的setInterval内部等待?

如何在JS的setInterval内部等待?
EN

Stack Overflow用户
提问于 2018-08-14 04:37:30
回答 6查看 24.8K关注 0票数 16

我有一个代码段,看起来像这样:

代码语言:javascript
复制
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方法的格式如下:

代码语言:javascript
复制
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错误。

代码语言:javascript
复制
 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());
            }
        });
    });
}
EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2018-08-14 04:46:31

相反,将interval函数转换为递归setTimeout函数,这样一旦函数完成,您就可以为下一次迭代初始化超时。

代码语言:javascript
复制
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);
票数 12
EN

Stack Overflow用户

发布于 2018-12-26 21:18:26

使用以下代码:

代码语言:javascript
复制
setInterval(async () => {
    await fetch("https://www.google.com/") 
}, 100);
票数 27
EN

Stack Overflow用户

发布于 2019-08-28 02:24:15

我通常选择这种解决方案。我认为它更干净:

代码语言:javascript
复制
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。您可以等待它停止循环,也可以丢弃它。

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51830200

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档