Thank you Scotty. You are determined to compel me to engage with you aren't you? That's ok. I'm into it. Honored really. I've noticed many of your comments on the TC-39 proposals github issues I follow ('m just a lurker). I feel like a small fish not worth the attention being paid to me, so thank you again.
I don't have anywhere near the technical expertise you seem to have so I appreciate the added context you bring.
```
await result = fetch(url).then(x => x.json())
```
I've seen this several times. It's nice. I like it. I don't like it for me over the plain promise version though. In my usage, I tend to value consistent mental models over some other virtues. Not everyone has the same preferences, and that's fine.
> your example with .catch() becomes much less pretty if we try to make .catch() apply to only a small scope.
```
doTask()
.then(x => nextTask(x)
.catch(handleError)
)
.then(x => anotherTask(x))
.then(x => finalTask(x))
```
Not so. The above can also be written as:
```
doTask()
.then(x => nextTask(x))
.catch(handleError)
.then(x => anotherTask(x))
.then(x => finalTask(x))
```
Runnable example:
```
Promise.resolve('{ answer: wrong')
.then((str) => JSON.parse(str))
.catch((error) => (console.log(error), {answer: 21}))
.then(({ answer }) => answer * 2)
.then((answer) => console.log(answer))
```
The above logs the error then logs the correct answer.
I suppose your point though, is that the catch in my example would catch any error that happened above it, not just the immediately preceding one. That's true. But if we need to do something like that, your earlier example is not all that bad, though I might write it slightly differently.
```
doTask()
.then(x => nextTask(x).catch(handleError))
.then(x => anotherTask(x))
.then(x => finalTask(x))
```
Finally, handling the early return problem is really just a matter of rethrowing something in the `handleError` function, isn't it?
Let me reverse-engineer your reverse-engineering...
```
const x = await doTask()
let y
try {
y = await nextTask(x)
} catch (err) {
handleError(err)
return
}
const z = await anotherTask(y)
const w = await finalTask(z)
```
becomes:
```
doTask()
.then(nextTask)
.catch((err) => {
handleError(err);
return Promise.reject()
})
.then(anotherTask)
.then(finalTask)
```
Presumably, these are in functions and are meant to resolve/return a value of some kind which neither of these examples show. But in that case, it really just a matter of rejecting with the value you want to ultimately resolve with.
```
const getResult = () => doTask()
.then(nextTask)
.catch((err) => {
handleError(err);
return Promise.reject(defaultValue)
})
.then(anotherTask)
.then(finalTask)
.catch((val) => val)
```
The final catch functions as an early return handler. It's not a situation that comes up often though. Typically, I catch early and provide a default value. I don't think I've used the second parameter of `then` since the jQuery days.
If things get much more complicated that this, I don't know that async/await offers a better alternative. Inherent complication is, well, inherently complex. But removing unnecessary complexity is a quality I strive for, and in doing that, I don't tend to run into many of the issues you've pointed out.
That said, if I did come across an area where I felt async/await genuinely provided a better experience, I would use it.
Anyway. Thanks for the engagement! I genuinely enjoy it.