Дождитесь завершения асинхронной рекурсивной функции, прежде чем переходить к следующей строке кода - PullRequest
0 голосов
/ 28 сентября 2018

Я пытаюсь дождаться полного завершения рекурсивной функции, прежде чем перейти к следующей строке кода.Я использую 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 ()?Как это будет работать с рекурсией?Любая помощь будет оценена.

1 Ответ

0 голосов
/ 28 сентября 2018

Я бы предложил использовать цикл, из которого вы выходите при успешном завершении, потому что тогда нет никакого наращивания ресурсов каким-либо образом (например, обещаний), и вы можете вызывать свою функцию бесконечное количество раз, если это требуется, без нагрузки на использование ресурсов..

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;
        }
    }
}
...