chapter eight

8 Scheduling

 

This chapter covers

  • Identifying the "unnamed monster" causing identical code to produce different results
  • Tracing how runtime-specific task queues determine callback execution order
  • Recognizing when the "drain until empty" rule starves your event loop
  • Comparing scheduling APIs across multiple JavaScript runtimes
  • Writing async code that depends on explicit ordering

So far we’ve covered how functions work, how objects hold state, and how errors propagate. Those are the building blocks. From here, we start looking at the mechanisms that coordinate them across time.

Back when I was consulting with customers to help them identify performance bottlenecks and bugs in their Node.js applications, I would typically lead the conversation with a question: is your application using Promises? If they said yes, without even looking at the code first I’d make an assertion that would often catch them off guard: “If you’re using promises, you’re likely using them wrong”.

At first glance, this seems a bold and potentially arrogant assertion, and I’ve had quite a few engineering teams rightfully push back on it. What I’ve learned, however, is that while most developers understand what promises are used for, they tend to skip over how they work and how they interact with other parts of the application, and it is that gap that often leads to problems.

8.1 The monsters in your async code

8.2 What “asynchronous” actually means

8.3 The anatomy of a promise

8.4 The multi-queue model

8.4.1 Jobs

8.4.2 Queues

8.4.3 Isfet at work

8.4.4 Our friendly puzzle, solved

8.4.5 When microtasks drain

8.5 Taming the monster

8.5.1 Implicit vs explicit ordering

8.5.2 Use the queues correctly

8.5.3 Context determines order

8.5.4 Reality isn’t a puzzle

8.6 Summary