Python for JS Devs · Fundamentals
You already understand the event loop better than most Python devs. Here's how that knowledge maps — and the one place it doesn't.
This lesson is your bridge into FastAPI. Python's async/await is modelled on the same single-threaded, cooperative event loop you know from Node — but with a few explicit steps JS hides.
async function getUser(id) {
const res = await fetch(url);
return res.json();
}async def get_user(id: str):
async with httpx.AsyncClient() as c:
res = await c.get(url)
return res.json()async def defines a coroutine; await suspends it until the awaited thing resolves. Same mental model as JS.
async function starts it immediately and returns a Promise that's already running. In Python, calling get_user() returns a coroutine object that has not started. Nothing runs until you await it or hand it to the event loop. A common beginner bug is calling an async function and forgetting to await it — you get a "coroutine was never awaited" warning and no work happens.
In Node the loop is always running. In a plain Python script you must start it with asyncio.run() at the top level. Inside FastAPI you won't do this — FastAPI runs the loop for you — but you need to know it exists.
import asyncio
async def main():
await get_user("42")
asyncio.run(main()) # starts the loop; the entry point
gather ≈ Promise.allconst [a, b] = await Promise.all([
getUser("1"),
getUser("2"),
]);a, b = await asyncio.gather(
get_user("1"),
get_user("2"),
)Awaiting them one after another is sequential (slow); gather runs them concurrently on the one loop — exactly like Promise.all.
time.sleep, heavy CPU work) freezes the entire loop — every other request waits. This is the same "don't block the event loop" law you live by in Node. Lesson 17 is entirely about the FastAPI version of this trap. Async libraries (httpx.AsyncClient, async DB drivers) exist precisely to avoid it.
Write a script with async def slow(n): await asyncio.sleep(1); return n. First await two calls sequentially (feel the ~2s), then run them with asyncio.gather (feel the ~1s). Seeing concurrency collapse the time — and knowing it's the same loop you know from Node — is the win.
async def function returns:await it.Promise.all is:asyncio.gather(...) runs awaitables concurrently on one loop.asyncio.create_task do? Perfect question before FastAPI.