次のようなコードセグメントがあります。
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());
}
});
});
}
間隔関数を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);
次のコードを使用します。
setInterval(async () => {
await fetch("https://www.google.com/")
}, 100);
誰かが更新されたソリューションを必要とする場合、ラップされたコンポーネントがアンマウントされると、残存タイマーを自動的にキャンセルする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);
}
}
代わりに間隔を関数にして、setTimeoutを使用して将来の関数呼び出しをキューに入れます。
const interval = async function () { // instead of setInterval
次に、将来の呼び出しをキューに入れたい場所でsetTimeout関数を使用します。
setTimeout(interval, 2000);
フィドルの例: http://jsfiddle.net/t9apy3ec/5/