在puppeteer / JavaScript中重试page.goto,page.waitForNavigation等的最佳实践

时间:2019-07-04 09:00:36

标签: javascript node.js async-await puppeteer tor

我正在尝试使用Puppeteer和tor软件包(apt install tor)在TOR网络中抓取一些网页。 可能由于TOR连接的性质,有时我会超时。 另外,我是JavaScript异步编程的新手。

通常,我有一个try-catch-construct像这样:

await Promise.all([
  page.goto(url),
  page.waitForNavigation({
    waitUntil: 'domcontentloaded'
  }),
]).catch((err) => { logMyErrors(err, true); });

let langMenu = await page.waitForXPath('//*[contains(@class, ".customer_name")]/ancestor::li').catch((err) => { logMyErrors(err, true); });

但是我认为通常一次或多次重试将有助于最终获得所需的资源。是否有实施重试的最佳实践?

2 个答案:

答案 0 :(得分:1)

我推荐这种相当简单的方法:

async function retry(promiseFactory, retryCount) {
  try {
    return await promiseFactory();
  } catch (error) {
    if (retryCount <= 0) {
      throw error;
    }
    return await retry(promiseFactory, retryCount - 1);
  }
}

此函数调用promiseFactory,并等待返回的Promise完成。万一发生错误,该过程将(递归)重复进行,直到retryCount到达0

代码示例

您可以使用以下功能:

await retry(
  () => page.waitForXPath('//*[contains(@class, ".customer_name")]/ancestor::li'),
  5 // retry this 5 times
);

您还可以传递其他任何返回Promise的函数,例如Promise.all

await retry(
  () => Promise.all([
    page.goto(url),
    page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
  ]),
  1 // retry only once
);

不要将等待和捕获结合在一起

另一建议:您不应将await.then.catch结合使用,因为这会导致意外的问题。使用await并用try..catch块包围代码,或者使用.then.catch。否则,您的代码可能正在等待catch函数的结果完成,等等。

相反,您可以像这样使用try..catch

try {
  // ...
} catch (error) {
  logMyErrors(error);
}

答案 1 :(得分:0)

这里有一个重试的例子,没有失败的金字塔。 我不是ES专家,并且可能会有一些新的异步/等待功能可以使代码更简洁,但现在可以使用:

function retry(callback, retries) {
    let tries = 0;

    function tryRequest() {
        tries++;
        return callback().catch(e => {
            logMyErrors(e);

            if (tries < retries) {
                return tryRequest();
            }
        });
    }

    return tryRequest();
}

const logMyErrors = console.log;


retry(() => {
    console.log("retry");
    return new Promise((resolve, reject) => {
        //Emulate some rejections here
        if (Math.random() > 0.2) {
            throw new Error("Something went wrong."); 
        }

        resolve("Success");
    });
}, 10).then((result) => {}, (rejected) => {});

函数retry接受一个回调,该回调必须返回承诺。执行callback直到Promise完成(解决,拒绝)或达到retries的数量。