web-dev-qa-db-ja.com

JSのsetInterval内で待機する方法は?

次のようなコードセグメントがあります。

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);
    });
}

今問題は、私のコードがスクロールし続けることですが、2秒ごとにスクロールし続けるので、setInterval内の他のものが完了するのを待ちませんが、通常、extractDate関数は2秒より長いので、新しいインターバルを呼び出す前に、setInterval内のすべてのものが終了するのを実際に待ちます。

ものの非同期の性質のため、私はconsole.logスタッフなので、コードの動作を確認してください。

それで、次のインターバルコールを行う前に、setInterval内のすべてが完了していることをどのように確認できますか?

編集:

setTimeoutを使用するこのソリューションは、1回だけスクロールし、操り人形師で未処理のプロミス拒否エラーをスローします。

 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());
            }
        });
    });
}
7
tinker

間隔関数をrecursive setTimeout functionに変換します。これにより、関数が終了したら、次の反復のタイムアウトを初期化できます。

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);
1

次のコードを使用します。

setInterval(async () => {
    await fetch("https://www.google.com/") 
}, 100);
1
Zeeshan Ahmad

誰かが更新されたソリューションを必要とする場合、ラップされたコンポーネントがアンマウントされると、残存タイマーを自動的にキャンセルする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);
    }
  }
0
Novice_JS

代わりに間隔を関数にして、setTimeoutを使用して将来の関数呼び出しをキューに入れます。

const interval = async function () { // instead of setInterval

次に、将来の呼び出しをキューに入れたい場所でsetTimeout関数を使用します。

setTimeout(interval, 2000);

フィドルの例: http://jsfiddle.net/t9apy3ec/5/

0
Gustav G