import { future } from "@mdx-deck/themes"; import { syntaxHighlighter } from "mdx-deck/themes"; export const themes = [future, syntaxHighlighter]; import { SplitRight } from "mdx-deck/layouts"; import { Steps, Appear } from "@mdx-deck/components"; import { Image, Notes } from "mdx-deck";
NodeJS Asynchronicity
Basics, Common Pitfalls & Solutions
<Steps length={2} render={({ step }) => ( <img src={"./static/el" + step + ".png"} /> )} />
-
Event loop can be visualized like so
-
Next slide: better to show it like this
-
Next slide: or maybe like Life Cycle Events
-
Next slide: Event Loop is a flat circle
- NodeJS / V8 is single threaded
- Async = non-blocking
- Promises are async
- but are they non-blocking?
- In all seriousness...
-
Using this visualization of the Event Loop
-
Go over each "Phase"
- setTimeout() / setInterval() calls
- Timer ms must have passed before evaluating
- Evaluated once per loop in NodeJS
- Brower handles this differently (but that's a different talk)
setTimeout(, 0)
===setTimeout(, 1)
- Always at least 1ms wait
- nextTick / micro tasks
- "micro tasks" = Promise callbacks
- Occurs between each Event Loop "Phase"
- Node v11 and up handles this differently 😱
- Phase ends when queue exhausted
- Reolved Pomises in this phase are added back into this queue
- Can result in "I/0 starvation", e.g. blocking the event loop
- e.g. handle incoming API requests, disk I/O, DNS lookups
- Complex and varies based on host OS
- setImmediate() calls
- Callbacks added to setImmediate queue during this phase will be evaluated on next pass of the event loop
- process.exit() and crashes of NodeJS process
- Important for scripts, but generally not important in context of an API server
- Last opportunity to cleanup before Node process is terminated
- e.g. Draining database connections
DEMO: Promise.resolve / setTimeout / setImmediate
- Browser: nextTick callbacks and microtasks will run between each individual setTimeout and setImmediate callbacksdemo blocking event loop on API server here and how to solve it
Ping API server every second:
while true; do date && curl -m 5 http://localhost:5000/api/auth && echo; sleep 1; done
Blocking v Non-Blocking API requests:
START=$(date +%s) && curl http://localhost:3000/loop && END=$(date +%s) && echo "Took: $(expr $END - $START) sec"
START=$(date +%s) && curl http://localhost:3000/loop/bmap && END=$(date +%s) && echo "Took: $(expr $END - $START) sec"
START=$(date +%s) && curl http://localhost:3000/loop/seti && END=$(date +%s) && echo "Took: $(expr $END - $START) sec"
START=$(date +%s) && curl http://localhost:3000/loop/bird && END=$(date +%s) && echo "Took: $(expr $END - $START) sec"
START=$(date +%s) && curl http://localhost:3000/loop/native && END=$(date +%s) && echo "Took: $(expr $END - $START) sec"
START=$(date +%s) && curl http://localhost:3000/loop/sett && END=$(date +%s) && echo "Took: $(expr $END - $START) sec"
"The fair treatment of clients is thus the responsibility of your application." -NodeJS Docs
Partitioning on the Event Loop Paradigm
show refactor of Admins Partners Report hereimport { Split } from "mdx-deck/layouts";
-
NodeJS Event Loop series - Deepal Jayasekara
-
Node.js: How even quick async functions can block the Event-Loop, starve I/O - Michael Gokhman
-
[OFFICIAL] The Node.js Event Loop, Timers, and
process.nextTick()
- Event Loop: NodeJS vs Browser
- How NodeJS v11 changes async resolution