J'ai un segment de code qui ressemble à ceci:
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());
}
});
});
}
Où la méthode extractDate
a la forme suivante:
function extractDate(html) {
return new Promise((resolve, reject) => {
// Rest removed for brevity.
resolve(result);
});
}
Maintenant, le problème est que mon code continue de défiler, mais il n'attend pas que les autres éléments de setInterval
se terminent, car il continue de défiler toutes les 2 secondes, mais normalement la fonction extractDate
devrait prendre plus de 2 secondes, donc je veux vraiment attendre que tout dans setInterval
se termine avant de faire l'appel au nouvel intervalle.
En raison de la nature asynchrone des choses, je n'ai pas réussi à console.log
stuff donc voyez le comportement du code.
Alors, comment puis-je m'assurer que tout à l'intérieur de setInterval
se termine avant de passer le prochain appel d'intervalle?
MODIFIER:
Cette solution utilisant setTimeout
défile une seule fois et génère une erreur de rejet de promesse non gérée avec le marionnettiste.
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());
}
});
});
}
Transformez la fonction d'intervalle en fonction récursive setTimeout
à la place, de cette façon, vous pouvez initialiser un délai d'attente pour l'itération suivante une fois la fonction terminée.
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);
Utilisez le code suivant:
setInterval(async () => {
await fetch("https://www.google.com/")
}, 100);
Si quelqu'un veut une solution mise à jour, il existe un délai de réaction qui annule automatiquement tous les temporisateurs persistants lorsque le composant encapsulé est démonté.
Plus d'informations
https://www.npmjs.com/package/react-timeout
npm i react-timeout
Pendant que vous attendez, vous pouvez faire quelque chose comme ça
handleClick = async() => {
try {
await this.props.getListAction().then(()=>{
this.timeOut = this.props.setTimeOut(this.handleClick, 10000);
});
} catch(err) {
clearTimeout(this.timeOut);
}
}
Faites plutôt de l'intervalle une fonction et utilisez setTimeout pour mettre en file d'attente le futur appel de fonction.
const interval = async function () { // instead of setInterval
Ensuite, utilisez la fonction setTimeout où vous souhaitez mettre le futur appel en file d'attente:
setTimeout(interval, 2000);
Exemple de violon: http://jsfiddle.net/t9apy3ec/5/