1. do notation works and is used for any monadic type (e.g. lists, parsers, promises, resources like database-connection-contexts, ...) while async/await works for promises only
2. async works on the function-level and only there while do-notation can be used in any place where a normal expression can be used, including being abitrarily nested.
There are more differences, but that should be enough food for the mind to think about it.
You could summarize it as: async/await makes it easier to work with promises on the syntax level and trying to make async code look like sync code, while the do-notation does not try to make async code to look like sync code, but rather embrace that sometimes two different semantical flows are interwined (one inside a monadic context, one pure) and makes it easier to work with them on the syntax level while at the same time making the two look _different_ explicitly.
From the perspective of someone wanting to use the powerful do-notation, sure. But at the same time, the hurdle for many developers who just want to "use promises with ease", it would have been a steeper learning curve with much less beginner-friendly syntax.
do-notation doesn't really help to deal with promises, it even makes it harder because it is confusing at the beginning. Async/await makes using promises easier and hides problems for some time at least. I can see why they chose to use async/await.
Just to give an example: error handling with try/catch. That doesn't work with do-notation, but with async/await you can integrate it (more or less at least) and it looks like sync code.
1. do notation works and is used for any monadic type (e.g. lists, parsers, promises, resources like database-connection-contexts, ...) while async/await works for promises only
2. async works on the function-level and only there while do-notation can be used in any place where a normal expression can be used, including being abitrarily nested.
There are more differences, but that should be enough food for the mind to think about it.
You could summarize it as: async/await makes it easier to work with promises on the syntax level and trying to make async code look like sync code, while the do-notation does not try to make async code to look like sync code, but rather embrace that sometimes two different semantical flows are interwined (one inside a monadic context, one pure) and makes it easier to work with them on the syntax level while at the same time making the two look _different_ explicitly.