1

I'm hoping someone can suggest a better method for what I'm trying to achieve.

While performing a rather long and complicated webflow using puppeteer, occasionally an error will occur that disrupts the actions I'm trying to take on the page. There's nothing I can do about it in these situations other than return a useful error. However it doesn't happen often enough to explicitly wait and try to catch it after each step in my code.

The solution I have is:

async function runCode() {
    try {
         const page = browser.open(url)
          listenForError(page)
          await longWebFlow()
    } catch (err) {
      return err.message
    }
}

async function listenForError(page) {
  await page.waitForXPath(errorMessageXPath)
  throw new Error('Error found!')
}

try {
    await runCode()
} catch (err) {
console.log(err.message)
// should print('Error found')
}

Obviously, the unawaited listenForError call won't be caught in the try/catch, but I also cant await the call, or else I'll never get to the main part of the code.

The code works to short-circuit the process and return, since the error occurred, but how can I refactor this to catch the error message?

1
  • I don't know puppeteer, but do you need to somehow cancel the waitForXPath() call after the longWebFlow() is done, to avoid leaking resources? Commented Dec 13, 2022 at 20:24

2 Answers 2

4

It seems like you want to wait until either the error is thrown or the longWebFlow() finishes - basically doing both concurrently. That's a perfect use case for promises with Promise.race:

async function runCode() {
    const page = browser.open(url)
    await Promise.race([
        listenForError(page),
        longWebFlow(),
    ]);
}

You could also use Promise.all if you made longWebFlow cancel the listenForError and fulfill the promise.

Either way, since you can properly await the promises now, the error also will be caught in the try/catch, as it should.

Sign up to request clarification or add additional context in comments.

1 Comment

I knew I was missing something obvious. Thanks!
1

If you can't await the async operation then the only other "follow up" is with callbacks like .then() and .catch(). For example, you can catch the error here:

listenForError(page).catch(e => console.log(e));

This won't await the operation, it's just supplying a callback for whenever that operation fails at whatever point in the future.

5 Comments

gotcha -- the only way I can think to make that work is to wrap the whole thing in a Promise, which I'm trying to avoid
@CameronSima: What needs to be wrapped in a Promise? The listenForError function already returns a Promise, this is just appending a callback to that Promise.
the whole code block. The purpose is to get the error message out of this function call and back to the caller, not to console.log it
@CameronSima: You don't have to log it to the console, you can do whatever you like with the error in the callback function. console.log is just a simple illustration of "doing something with the result". What are you trying to do with the result that you otherwise can't?
Sorry, I realized my question wasn't really that clear. Updated the question

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.