tin*_*ker 5 javascript asynchronous promise async-await 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 = 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());
}
});
});
}
Run Code Online (Sandbox Code Playgroud)
其中extractDatemethod具有以下形式:
function extractDate(html) {
return new Promise((resolve, reject) => {
// Rest removed for brevity.
resolve(result);
});
}
Run Code Online (Sandbox Code Playgroud)
现在的问题是,我的代码一直在滚动,但是它并不等待内部的其他东西setInterval完成,因为它每2秒滚动一次,但是正常情况下extractDate功能应该花费超过2秒的时间,因此我实际上想等待setInterval调用新间隔之前,内部的所有内容均要完成。
由于东西的异步特性,我没有设法去console.log东西,所以请看一下代码的行为。
那么,如何setInterval在下一次间隔调用之前确保内部的所有内容都完成了?
编辑:
该解决方案setTimeout仅滚动一次,并向操纵up抛出未处理的承诺拒绝错误。
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());
}
});
});
}
Run Code Online (Sandbox Code Playgroud)
Cer*_*nce 11
将间隔函数改为递归setTimeout函数,这样您就可以在函数完成后为下一次迭代初始化超时。
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);
Run Code Online (Sandbox Code Playgroud)
Wil*_*ner 10
我通常选择这个解决方案。我认为它更清洁:
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
async function loop() {
while (/* condition */) {
/* code to wait on goes here (sync or async) */
await delay(100)
}
}
Run Code Online (Sandbox Code Playgroud)
您的loop函数将返回一个承诺。您可以等待它停止循环,也可以丢弃它。
小智 6
将间隔设置为一个函数,并使用 setTimeout 对未来的函数调用进行排队。
const interval = async function () { // instead of setInterval
Run Code Online (Sandbox Code Playgroud)
然后使用 setTimeout 函数将未来的调用排队:
setTimeout(interval, 2000);
Run Code Online (Sandbox Code Playgroud)
小提琴示例: http: //jsfiddle.net/t9apy3ec/5/
使用以下代码:
setInterval(async () => {
await fetch("https://www.google.com/")
}, 100);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7177 次 |
| 最近记录: |