首页 > 解决方案 > 在继续执行下一行代码之前等待异步递归函数完成

问题描述

我正在尝试等待递归函数完全完成,然后再继续执行下一行代码。我正在使用 PuppeteerJS 在页面上查找项目,如果该项目不存在,3 秒后重新加载页面并重试。在继续之前,我需要完成此功能。我在下面尝试实现的简单代码示例。

(async () => {
    await waitForThisToFinish() // Wait for this function no matter how long it takes
    console.log("Don't log until function has completed")
})()

async function waitForThisToFinish() {
    try {
        await findItemOnPage()  //function times out after 3 seconds
    }
    catch (ex) {
        // If Item is not found after 3 seconds an error is thrown.
        // Catch error and reload page to see if item has been loaded and look again.
        waitForThisToFinish() //recursive call
    }
}

目前,如果第一次尝试未找到该项目,则会引发错误并成功开始递归。但是,代码执行会继续,并且不会等待函数成功完成。

有没有办法让'catch'无法解决?我需要从 waitForThisToFinish() 函数返回一个承诺吗?这将如何与递归一起工作?任何帮助,将不胜感激。

标签: javascriptrecursionpromisepuppeteer

解决方案


我建议使用一个循环,当成功时你会中断,因为这样就不会以任何方式(如承诺)建立资源,并且如果需要,你可以无限次调用你的函数,而不会强调资源使用。

async function waitForThisToFinish() {
    while (true) {
        try {
            let val = await findItemOnPage()
            // use break or return here to break out of the loop
            return val;
        } catch (ex) {
            console.log("still waiting and trying again")
        }
    }
}

此外,您还应该进行一些额外的更改:

  1. 检查实际错误以确保它是可以通过重试修复的错误类型(例如超时)。如果这是一个永久性错误,您将永远重试。
  2. 在重试之前实施延迟以避免在服务器端造成雪崩故障并避免服务器因速率限制而阻塞。
  3. 在延迟中实施渐进式退避。

因为您通常不想编写代码来敲击服务器(通过快速连续地反复发出相同的请求),因为这可能会导致雪崩服务器故障,一个小问题变成一个大问题非常很快,您可能应该在重试之前实施延迟,问题持续的时间越长,延迟就会越长。

function delay(t) {
    return new Promise(resolve => {
        setTimeout(resolve, t);
    });
}


async function waitForThisToFinish() {
    let waitTime = 100;
    while (true) {
        try {
            let val = await findItemOnPage()
            // use break or return here to break out of the loop
            return val;
        } catch (ex) {
            // Should also check if the actual error is one that is likely
            // temporary.  Otherwise, you may loop forever on a permanent error
            console.log("still waiting and trying again")
            // implement super simple backoff (there are much more elegant algorithms available)
            await delay(waitTime);
            waitTime += 300;
        }
    }
}

推荐阅读