如何在JS的setInterval内部等待? [英] How to await inside setInterval in JS?

查看:111
本文介绍了如何在JS的setInterval内部等待?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆