Part of the problem in JS is that there's pretty much 2 classes of functions. Asynchronous functions and synchronous functions. Both are extremely common.
Async/await solves this to some extent, because you can just go back to 1 way of error handling, which is throwing and catching exceptions.
The third way (working with EventEmitter) is an odd pattern, but it's really more for specialized use-cases. Wouldn't really call this standard. Imagine a long-running operation that can occasionally broadcast that a non-fatal error occurred.
A global error number is a terrible idea, and return codes are not just not idiomatic.
So really there's just two: one for synchronous and one for asynchronous operations.
You'd be in a very similar situation with C. I don't know C too well, but I imagine that most asynchronous operations would be done with threads, and for those operations you also can't just return an error code.
Does Ruby have concurrency or async primitives? I don't know it really well. If it doesn't, it's also obvious why you wouldn't have this problem. If it does, how do you handle exceptions in asynchronous operations? To me it seems that Javascript, Ruby, C, PHP, Java are all pretty similar in these regards and JS is not at all unique.
Go gets this right. The equivalent of this ES7 function call in javascript:
await foo();
In go is a straight up regular function call:
foo();
But not waiting for the result in javascript:
foo();
Is actually handled with the go keyword:
go func();
This, to me, is the major difference in the asynchronous model between Go and Javascript. In javascript (with ES7) blocking is opt-in, in Go it's opt-out. Go is by far the saner model for a programming language that relies heavily on 'green threads' / reactor pattern.
The trouble with "go foo()" is that it's fire-and-forget; foo's return value is literally discarded. When you need to know what happened (which should be nearly always), foo and every caller all have to opt-in to passing any result and/or error and/or panic value over a channel or something. It's one of many places where Go gives you tiny pieces of the right thing and makes you assemble them yourself.
Either that or you wrap it up in function that makes a channel, calls the function with it, then waits on that channel for the return value. Basically you can go back/forth between async and sync(ish) in go much more easily than in JavaScript.
In saying that though, if you have to do it a lot it probably means some of those functions should have been synchronous in the first place.
Async/await solves this to some extent, because you can just go back to 1 way of error handling, which is throwing and catching exceptions.
The third way (working with EventEmitter) is an odd pattern, but it's really more for specialized use-cases. Wouldn't really call this standard. Imagine a long-running operation that can occasionally broadcast that a non-fatal error occurred.
A global error number is a terrible idea, and return codes are not just not idiomatic.
So really there's just two: one for synchronous and one for asynchronous operations.
You'd be in a very similar situation with C. I don't know C too well, but I imagine that most asynchronous operations would be done with threads, and for those operations you also can't just return an error code.
Does Ruby have concurrency or async primitives? I don't know it really well. If it doesn't, it's also obvious why you wouldn't have this problem. If it does, how do you handle exceptions in asynchronous operations? To me it seems that Javascript, Ruby, C, PHP, Java are all pretty similar in these regards and JS is not at all unique.
Go gets this right. The equivalent of this ES7 function call in javascript:
await foo();
In go is a straight up regular function call:
foo();
But not waiting for the result in javascript:
foo();
Is actually handled with the go keyword:
go func();
This, to me, is the major difference in the asynchronous model between Go and Javascript. In javascript (with ES7) blocking is opt-in, in Go it's opt-out. Go is by far the saner model for a programming language that relies heavily on 'green threads' / reactor pattern.