How to use async/await to handle a response

I’ve been trying to adopt async/await as much as possible, but the following async function fails with the error message:

Here is the code content in search_results.js:

const logToConsole = true;

(function(){
    if (logToConsole) console.log(`Requesting search results..`);
    requestSearchResults();
}())

async function requestSearchResults(){
    try {
        let response = await browser.runtime.sendMessage({action: "returnSearchResults"});
        handleResponse(response);
    } catch (err) {
        if (logToConsole) {
            console.error(err);
            console.log("Failed to retrieve search results.");
        }
    }
}

function handleResponse(content) {
    if (logToConsole) console.log(content);
    if (content === undefined || content === null || content === "") return;
    let results = document.getElementById("results");
    let doc = results.contentWindow.document;
    let h = window.innerHeight + "px";
    results.style.height = h;
    doc.open();
    doc.write(content);
    doc.close();
}

You shouldn’t use try / catch for promises, instead use .catch handler (you can also use .then with the second function parameter).
For example:

const response = await browser.runtime.sendMessage({action: "a"}).catch(err => {
  console.error(err);
  return 'backup response';
}
// warning,`response` will be 'backup response' in case of errors

The nice thing about async functions, is that all errors will automatically bubble up the promise chain. So make sure to use .catch on the right place, maybe on the requestSearchResults().catch(console.error).

See the docs:

Also if you need to reject a promise in your async function, just return Promise.reject() (as an equivalent of throwing an exception, which would work as well).

What is the reason for not using try/catch for promises? I’ve replaced almost all my promises with async/await and used try/catch everywhere.

I put try/catch almost everywhere after seeing this example:

I changed the async function as follows, but I’m getting the same error message.

async function requestSearchResults(){
    const response = await browser.runtime.sendMessage({action: "returnSearchResults"})
    .catch(err => {
        if (logToConsole) console.error(err);
        return "Failed to retrieve search results.";
    });
    handleResponse(response);
}

Regarding the StackOverflow, I would say that’s a bad example, especially because he had to use the second await when extracting text value (else the try catch wouldn’t work). Very misleading… I would recommend checking the MDN docs for fetch examples.

The reason for not using try catch is that you can easily miss exception because it will happen in a different “thread” asynchronously, even if it’s inside the try catch block. And the StackOverflow code is a nice example, by removing the second await the try catch would stop working for errors from response.text() promise.

Regarding your new code, are you sure the error is generated by the line:

if (logToConsole) console.error(err);

Also, if are you rejecting things manually, make sure to use Error object to get the stack trace info.

There is also a chance that this is just a runtime Firefox glitch and you just have to restart Firefox :slight_smile: (or use Chrome to track that bug down…)

I disagree with that. That’s one of the main features of async functions, that you can handle rejections without passing a catch callback.

As to the original problem, to find out what the actual error is, check the proper console, as documented on https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Debugging

Some errors can not be displayed in the Browser Console because they come from different processes.

Edit:

That doesn’t sound like an issue that using .catch() would solve. If you don’t await a promise in an async function, that’s the far bigger issue.

Please see the StackOverflow code again:

return await response.text();

In async function you DON’T have to use await for the returned value even if it’s a Promise because you can just return Promise and it will still be part of the main async function!

In most cases, yes. You want to return await if you want to handle rejections before returning though.