Node js async as colored function (2026)
JavaScript Async Functions Computation Model
a great article on the JavaScript async functions, an analysis of this computing model.
- What Color is Your Function? (JavaScript Async problems)
- By Bob Nystrom.
- https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/
node js async color function
- there is an article criticizing js async as colored function, summarize, and is it still valid, and what alternative it suggests
- What Color is Your Function?
- By Bob Nystrom
- https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/
2026-04-27 AI answer
The article you're referring to is "What Color is Your Function?" by Bob Nystrom (published February 1, 2015).
Summary of the Article
Nystrom uses a colorful metaphor to criticize JavaScript's (and Node.js's) asynchronous programming model at the time, which was dominated by callbacks (pre-async/await era). He imagines every function having one of two "colors":
- Blue functions = synchronous (normal functions that return values directly and can be called with regular syntax).
- Red functions = asynchronous (functions that "return" via callbacks or promises because they do I/O, timers, etc., and can't block).
He lists five rules that make this split painful and infectious:
- Sync functions return values; async ones invoke callbacks instead.
- The calling syntax differs (you pass a callback to red functions).
- You can't call a red (async) function from a blue (sync) one without special handling.
- Async functions are awkward in control flow, loops, conditionals,
try/catch, or higher-order functions (e.g., passing an async callback toArray.map). - Core libraries (file system, network, etc.) are async, so everything gets dragged into the "red" world.
The result: "color" spreads up the call stack. Once you touch any async API, your whole function (and every caller) has to become async too. This leads to "callback hell," brittle code, and poor composability. Nystrom argues this exposes low-level continuation-passing style (CPS) to application programmers—something that should stay hidden in compilers.
He notes that even async/await in languages like C# (which existed then) is just syntactic sugar: it makes red code look bluer, but the coloring and propagation issues remain.
Is It Still Valid in 2026?
Yes, the core criticism is still valid in modern JavaScript, though significantly mitigated.
async/await(standardized in ES2017 and now ubiquitous) dramatically improves readability and reduces callback/promise boilerplate. It lets red functions look almost like blue ones inside the function body.- However, the fundamental "coloring" problems persist:
- You still cannot
awaitin a non-asyncfunction (except limited top-levelawaitin modules). - Async "infects" callers up the stack.
- Higher-order functions (
map,filter,forEach, etc.) and libraries don't work seamlessly with async callbacks (you often needPromise.allwrappers or custom utilities). - Error handling, control flow, and reuse still feel different between sync and async code.
- Node.js's single-threaded event loop + promise-based async means the red/blue divide is baked into the language/runtime.
- You still cannot
Developers and discussions in 2024–2026 still reference the article when complaining about async propagation, especially in large codebases or when mixing sync libraries with async ones. The article's prediction that async/await is "better but not a full fix" has held up.
It is less painful than the 2015 callback era, but the structural issue Nystrom described hasn't been eliminated in JavaScript.
What Alternative Does It Suggest?
Nystrom argues the real solution is to eliminate function colors entirely by using languages or models with lightweight concurrency (multiple independent call stacks that can be suspended/resumed without exposing continuations to the programmer):
- Best examples: Go (goroutines + channels), Lua (coroutines), Ruby (fibers), or Erlang/Elixir (actors). In these, I/O looks synchronous, everything is the same "color," and you don't have to mark or propagate async.
- He contrasts this with threads (heavy) or generators/
yield(which are essentially isomorphic toasync/awaitand don't remove coloring).
In short: Prefer runtimes that give you green-thread-like concurrency so async I/O doesn't force a sync/async split at the language level. JavaScript's event-loop model (and similar designs in other languages) is the root cause, and no amount of syntax sugar fully solves it.
If you're dealing with this pain in a JS project today, common workarounds include careful use of async/await + Promise.all, libraries like p-map for async iterators, or (in Node) experimental sync I/O APIs where performance isn't critical—but none remove the coloring.