In this case, I'd like to write blocking-style code.
longjmp, however, is a crucial missing facility in JS. Emacs relies on it heavily in its design -- it's how catch / throw work, and it's why you can do things like
(catch 'foo
(map (fn (x)
(if (= x 42) (throw 'foo x)))
values))
Without longjmp, you can't do that. Just as you can't in JS.
So what? Well, that means you can't write emacs, because you're limited to what JS provides you. An entire class of software is beyond your ability to write, because you cannot provide the same features that other runtimes give.
This gets me started on the lack of any kind of reasonable error definitions in JS. In elisp, you define errors. Imagine you want to write some code that parses some parens -- it turns "(a b (c))" into ["a", "b", ["c"]]. What do you do when your program encounters "(a b" and then the end of the string? Throw a scan error!
Not in JS. It's considered poor manners to throw errors to the people using your library. Worse, it's a pain in the ass for users to catch and respond to errors. If you use someone's library, you usually don't expect to have to wrap it in a try-catch. And the code is massive:
try { operation } catch (e) { if (e instanceof ScanError) { do something else } }
Contrast that with elisp:
(condition-case nil
operation
(scan-error do something else))
There's no contest. It's way easier to write the latter than to use the tools JS gives you. But it's a cultural difference, and culture is slow to change.
That's why webassembly at least gives an escape hatch.