1

Looking for an explanation for why when calling a function within a try-catch with no prefix await it is ignored

Example:

async function foo() {
    try {
        return bar()
    } catch(e) {
        throw new Error('never see this')
    }
}

async function bar() {
    throw new Error('only see this')
}

foo().then()

When adding await it does reach catch:

async function foo() {
    try {
        return await bar()
    } catch(e) {
        throw new Error('now this works')
    }
}

async function bar() {
    throw new Error('foo')
}

foo().then()

The strange thing is when calling a function that is not async the try-catch does work with no issues:

async function foo() {
    try {
        return bar()
    } catch(e) {
        throw new Error('now this works')
    }
}

function bar() {
    throw new Error('foo')
}

foo().then()
MCMatan
  • 8,623
  • 6
  • 46
  • 85
  • This is the expected behavior. [Throwing inside an async function rejects the returned promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function#return_value). [Awaiting a rejected promise throws again](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#promise_rejection). – ASDFGerte Oct 03 '21 at 18:56
  • Since you don't `await` the return value of `bar` the first example the code runs synchronously and passes the catch block before the error is thrown (remember `bar` is `async`). When `await` the async value or you make `bar` synchronous then the un`await`ed synchronous `catch` block is triggered. – Jared Smith Oct 03 '21 at 18:57
  • @JaredSmith how does the try-catch get ignored? I would assume try-catch has an execution block that anything inside it is wrapped – MCMatan Oct 03 '21 at 19:01
  • 1
    @MCMatan it's not ignored, *the error hasn't been thrown yet when execution reaches that point*, so it doesn't trigger the catch. The Promise is returned while still pending. When you `await` the Promise is fulfilled before control flow moves to the return so the rejected Promise triggers the catch block. When you make it synchronous none of this applies and it just works like plain ol sync JS. – Jared Smith Oct 03 '21 at 19:02
  • It gets ignored because the error **has not happened yet**. The function call successfully returns a Promise without any errors. The promise object though captures the async error. You can access the async error by calling `bar().then(() => {}, (error) => {})` (the second function you pass to `.then()` or by calling `bar().catch((error) => {})` – slebetman Oct 03 '21 at 19:03
  • 1
    I think technically, the async function will run until an actually async part starts (first `await`) - meaning in this case, it will have thrown, before the block exits. This doesn't matter though, as mentioned above - throwing inside an async function just rejects the returned promise with the thrown value (and doesn't bubble the exception). – ASDFGerte Oct 03 '21 at 19:04
  • 1
    In simple terms, if `bar()` returns Promise, then ... (i) `return bar()` sees Promise, regardless of how that Promise eventually settles. (ii) `return await bar()` sees whatever the Promise settles to (result or Error). – Roamer-1888 Oct 03 '21 at 20:37

0 Answers0