ipmcc
ipmcc

Reputation: 29916

How do you wrap a call to an async function in order to wait for its completion?

I am writing a command-line tool in TypeScript. At one point, it needs to detect, synchronously -- no matter the delay -- whether a file on disk is an audio file. I'm using MediaInfo.js for this, and its API is, understandably, asynchronous, since media files can be huge. My goal is to create a synchronous function isAudioFile(...) that will invoke the MediaInfo.js async API, but somehow wait for a reply, and return true or false without itself becoming an async function.

I've tried just making everything async, but then I get errors from some portion of the toolchain about top level functions not being allowed to be async. I'm stuck on the versions of Node (14.15.1) and TypeScript (4.5.4) that I'm using for uninteresting reasons. I've started feeling like asynchrony in JS/TS is a kind of virus; it seems like it's just async/await all the way down.

I've asked several JS developers I trust and respect, and I've been told that this is "just not possible" and that I'm "thinking about it the wrong way", but no one has yet been able to tell me how I should be thinking about it, or how to solve the problem I'm facing.

Surely there must be some equivalent to a condition variable that I could wait on, even in a single-threaded, cooperatively-multitasked runtime like Node.js. I found JSZip-sync that seems to accomplish something similar, albeit with significant complexity. Is there really just no simple way to achieve this most seemingly-straightforward of tasks?

Upvotes: 1

Views: 1196

Answers (1)

Bergi
Bergi

Reputation: 664630

Is there really just no simple way to achieve this most seemingly-straightforward of tasks?

Yes, there really isn't.

Your "condition variable" idea doesn't work in a single-threaded runtime - if your single thread blocks on the variable, no other code can run that could change the variable's value.

There are a few complicated ways to achieve this (for example, running a subprocess with spawnSync), but they're no good.

I've been told that this is "just not possible" and that I'm "thinking about it the wrong way", but no one has yet been able to tell me how I should be thinking about it, or how to solve the problem I'm facing.

You should think about the problem in an asynchronous way. Interacting with the file system is asynchronous, it takes time to access those disks of spinning rust!

Yes, asynchrony is "infectious", because if one part of your function is asynchronous (and you need to think about arbitrary other code running in the mean time), the whole function is. However, that doesn't mean it needs to spread into your business logic.

"I get errors from some portion of the toolchain about top level functions not being allowed to be async" sounds like a solvable problem.

Upvotes: 2

Related Questions