If the program runs in single-threaded blocking mode async is forced to just call the function, however otherwise you still want to run the asynchronous code asyncronously. (not everyone wants to run their program in blocking mode and the code shouldn’t need to be changed to run it in non-blocking mode)
If you always just use function calls (and this code is part of a library) then the user doesn’t have the option to run it asynchronous.
io.async allows that, but if there is no possibility to have a background executor, you can still run the code in single threaded blocking mode, which is slower but enables more use cases. Giving more options to the user.
io.async enables implementation agnostic expression of the actual asyncrony and concurrency (via io.asyncConcurrent), allowing users to write the code once and use it with multiple different io implementations.