Monday, June 3, 2024
75
rated 0 times [  77] [ 2]  / answers: 1 / hits: 35601  / 6 Years ago, mon, august 13, 2018, 12:00:00

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


Where extractDate method has the following form:



function extractDate(html) {
return new Promise((resolve, reject) => {
// Rest removed for brevity.
resolve(result);
});
}


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.



Because of the async nature of stuff, I didn't manage to console.log stuff so see the behavior of the code.



So, how can I make sure that everything inside setInterval finishes before making the next interval call?



EDIT:



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

More From » asynchronous

 Answers
7

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

[#53741] Thursday, August 9, 2018, 6 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
raynamadilynl

Total Points: 653
Total Questions: 110
Total Answers: 98

Location: Honduras
Member since Sat, Jul 24, 2021
3 Years ago
raynamadilynl questions
;