V JS máte jistotu, že posloupnost operací přistupující ke sdíleným prostředkům proběhne bez přerušení. V Go tu jistotu nemáte.
Ale to přece není otázka blocking/non-blocking, ale důsledek toho, že JS nemá žádnou podporu pro multithreading (i user-level). Ale dobrá reklama na JS: je to super-jazyk, nemusíte řešit zámky, protože to neumí multithreading a rozhodně mezi 2 příkazy vám "omylem" nic nevleze, protože kód "po" tom prvním příkazu musíte dát jako callback a tím pádem je vidět, že tam něco vleze. Ale blbě se s tím programovalo, takže jsme vynalezli "async await", který způsobí, že vám mezi ty 2 příkazy něco klidně může vlízt a tím pádem se to chová jako ty všechny ostatní jazyky, ale jinak je to fakt lepší....
Awaitovat můžete jen uvnitř async funkce. Composable to je. Můžete awaitovat vše co vrací promise, tedy i jiné async funkce. Tomu tazateli by stačilo místo forEach použít obyčejný for.
Pythonovské generátory jsou composable. Co jiného dělá yield from?
Vida, vývoj pythonu už delší dobu nesleduju, to tam tehdy nebylo

Ovšem bez "yield from" to taky bylo composable, stačilo použít for...yield... to je v podstatě další syntaktický cukr, podobně jako async await. Prostě to není composable ale nějak to syntaxí přiohnem, aby se aspoň ty nejčastějc používané věci dali rozumně použít a člověk se přitom neškrábal nohou za uchem.
Ale jo, ty jazyky se postupně zlepšují. Ještě pár desítek let a budou všechny docela použitelné....
Dokonce můžete kombinovat generátory s async await a vytvářet async generátory. V Go podobné věci zdaleka tak elegantně zapsat nejdou.
Protože je (často) prostě zapsat nepotřebuju. Celý async-await je prostě automaticky zapnutý....