【发布时间】:2022-01-18 04:38:59
【问题描述】:
我在 Puppeteer 的页面上运行一系列函数。如果其中一个函数抛出,我会重试整个序列几次,因为我使用的系统不可靠。这比处理所有可能的异常要容易。
有时,其中一个步骤会挂起,而不是抛出,所以我想为了安全起见超时,然后像发生异常一样重试。
如果我不将我的序列包装在下面的asyncCallWithTimeout() 中,一切都会正常工作并解析为我想要的(一个数组)。但是,当我使用该函数时,我留下了一个未解析的函数,我将其传递为 asyncPromise。
在我的一生中,我无法弄清楚为什么 Promise.race() 会以我通过的未解决 asyncPromise 解决。我错过了什么?
这是在其他异步函数运行时间过长时使它们超时的函数:
async function asyncCallWithTimeout(asyncPromise, timeLimit) {
let timeoutHandle;
const timeoutPromise = new Promise((_resolve, reject) => {
timeoutHandle = setTimeout(
() => reject(new Error('Async call timeout limit reached')),
timeLimit
);
});
return Promise.race([asyncPromise, timeoutPromise]).then((result) => {
clearTimeout(timeoutHandle); // .then() looks to be executed every time even if timeout is set to 1 ms
return result;
});
};
const timer = ms => new Promise(r => setTimeout(r, ms));
const shouldResolve = asyncCallWithTimeout(timer(1000), 2000).then(console.log).catch(console.error);
const shouldReject = asyncCallWithTimeout(timer(2000), 1000).then(console.log).catch(console.error);
如果相关,这里是重试函数:
async function retry(promiseFactory, retryCount) {
try {
return await promiseFactory();
} catch (error) {
if (retryCount <= 0) {
throw error;
}
return await retry(promiseFactory, retryCount - 1);
}
};
我是这样用的:
async function checkT(browser, url) {
const tUrl = `https://example.com/?url=${url}`;
return retry(async () => {
const browserPage = await browser.newPage();
try {
return asyncCallWithTimeout(async () => { // works if this is commented
await browserPage.goto(tUrl);
await doSomething(browserPage);
await waitForSomething(browserPage);
const results = await getResults(browserPage);
await browserPage.close();
return results;
}, 10000); // works if this is commented
} catch (error) {
await browserPage.close();
throw error;
}
}, 3);
};
然后我在其他地方这样称呼它(使用p-queue,这是无关紧要的):
for (const page of pages) {
queue.add(() => checkT(browser, page.url)
.then(async (results) => {
// results should be an array but is a function and not iterable hence fails below
for (const result of results.data) {
// do something with the result
}
})
);
};
【问题讨论】:
-
我添加了一个可运行的 sn-p 来测试您的问题,但它似乎工作正常。具有较小超时的承诺是两个示例中的最终值。您可以修改该 sn-p 以重现您的问题吗?
-
你的
asyncCallWithTimeout期望得到一个承诺,但你却传递了一个async function。你也错过了try块中的await,通过立即returning 承诺拒绝不会导致catch子句运行。顺便说一句,我建议无论如何都使用finally作为browserPage.close() -
谢谢@Bergi。你能解释一下丢失的
await以及为什么直接的return永远不会触发catch?我很想阅读更多内容,但不知道要搜索什么。关于finally我想这只是你的个人喜好?
标签: javascript async-await promise puppeteer