the fact that there is a long chapter in a book series written on the edge cases of javascript[0] leads me to believe that it's not generally well understood either.
JS uses an event-loop (which is really just a variation of a message/event queue that we've been using for GUI based applications for decades now). If you understand this, asynchronous code in JS is pretty easy to understand.
async/await is pure sugar on top of promises (it's literally just wrapping the rest of the function in a .then() for you, and coercing the return value of your function to always be a promise)
IMO that's an explicitly different issue than a comparison between Promises/async/await and Ruby's metaprogramming, though.
Not to mention that part of the issue with Promises is the various polyfills invented before broad acceptance, which is a separate can of worms, and a different type of complexity than the (relatively) heavy use of metaprogramming in Ruby (relative to JS).
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Even...
You can go from nothing to mostly full-fledged promises in about 200 lines of code: ex - https://www.promisejs.org/implementing/
async/await is pure sugar on top of promises (it's literally just wrapping the rest of the function in a .then() for you, and coercing the return value of your function to always be a promise)