14.7 Async and await
- Approved by
- Panaversity ·
In everyday life. You have two errands: a suit at the dry cleaner and a prescription at the pharmacy. Each counter needs ten minutes. You can wait at one, then at the other. Or you can hand in both, take a ticket at each, and come back when both are ready. The waits overlap, so the total is the longest wait, not the two added up.
What you will learn. When slow calls can run at the same time, which failures are worth another try, and why every call needs a time limit.
Why it matters. Most of a program's time goes on waiting. And a call that hangs, which means it waits forever, stops the whole run when nobody is watching.
Why is most slow work waiting?
Because the slow part is usually somewhere else. The program sits idle while a server answers, a file arrives or a database replies.
- Async code lets a program start a slow task, do other work while it waits, and pick the result up when it is ready.
- A promise in TypeScript is like the ticket from the counter: it stands for a result that is not ready yet. This is a new meaning of the word, not the promise a signature makes in 13.5. Python's version is a coroutine, which differs in one way, as What if I forget
await? explains. awaitmeans "pause this function here until the result is ready". Work already started keeps running meanwhile, but the next line waits.
So two awaits in a row wait one after the other. To overlap two calls, start both, then wait for both together.
| Idea | TypeScript | Python |
|---|---|---|
| A function that can wait | async function | async def |
| Wait for one result | await promise | await coroutine |
| Start several and wait for all | Promise.all([a, b]) | asyncio.gather(a, b) |
| Give up after a time | AbortSignal.timeout(2000) on a fetch, in milliseconds | asyncio.timeout(2), in seconds |
| Run the program | In a module, Node lets you write await outside any function | asyncio.run(main()) |
When can two calls run at the same time?
Only when neither needs the other's answer. Vendors and open invoices are independent. Page 1 has to come first, because it says how many pages there are.
At work. The sample API waits 300 milliseconds per answer, and answers the first vendors call with 503. One after the other, Ana's client would take about 1.5 seconds: two vendor calls and three invoice pages. With vendors and invoices fetched at the same time, it takes about one second, set by the three pages.
Here are the two errands in code, done both ways. wait(300, "vendors") stands in for a slow call: it waits 300 milliseconds, then gives back "vendors". A clock reads the time before and after, in milliseconds. Predict both times.
// wait stands in for a slow call. You do not need to follow this line
const wait = (ms: number, label: string) => new Promise<string>((resolve) => setTimeout(() => resolve(label), ms));
// one after the other: wait at the first counter, then at the second
let start = performance.now();
const first = await wait(300, "vendors");
const second = await wait(300, "invoices");
console.log("one after the other", Math.round(performance.now() - start), first, second);
// at the same time: hand in both, then wait for both together
start = performance.now();
const both = await Promise.all([wait(300, "vendors"), wait(300, "invoices")]);
console.log("at the same time", Math.round(performance.now() - start), both);one after the other 602 vendors invoices
at the same time 300 [ 'vendors', 'invoices' ]Your times will differ by a few milliseconds.
Which errors are worth a retry, and how often?
Only those that can succeed next time, and only a few times. A 503 or a 429 may succeed on the next try. A 401 or 400 will fail again. Brightline's client retries once on 503 and never on anything else. A client that retries forever sends request after request while a server is down.
How long should a call wait?
Every call needs a deadline, a timeout on the whole call. A call with no timeout can wait forever, and the program waits with it. Brightline's client gives every call a two-second deadline, in both languages.
What if I forget await?
It depends on the language. Both mistakes are common in agent code, so check that every async call is awaited.
| Language | What happens without await |
|---|---|
| TypeScript | The call starts as soon as you make it, and await only waits for it. Forget await, and the call happens, but nobody waits for its result or its error. You handed in the suit and never went back. |
| Python | A coroutine does nothing until it is awaited or handed to asyncio.gather. Forget await, and the call never happens. You only filled in the order. Python warns that the coroutine was never awaited. |
Try it
The file in 14-7 runs two waits each way. Run it and investigate, as in 13.1.
Modify. Send: "Please add a third wait of the same length to both halves of the file. Don't run it yet." Predict both times. Then ask the agent to run it.
Make. Decide whether a client should try again after a 400, a 401, a 429 and a 503. Then start the sample API, and send: "Please make a new file in 14-7 called mine that asks the sample API for /vendors with the key from .env, tries again only as my rule says, gives every call a two-second deadline, and prints the status code of every try. Don't run it yet." Paste your rule. Read the lines that decide whether to try again, and then ask the agent to run it. Then ask it to stop the API.
What you should see. After your change, about 900 milliseconds one after the other, and still about 300 at the same time. In mine, a 503, then a 200 if your rule tries a 503 again, because the API's first /vendors answer is a 503 on purpose.
The operating rule: run slow calls at the same time only when they do not depend on each other. Retry only the errors that can succeed next time, and only a few times, and give every network call a deadline.

Figure 14.8. One after the other, or at the same time. In Brightline's client the pages run in turn, which is simpler. The vendors do not wait for them.
Next. Companies publish code that does all of this for you. 14.8 shows how to read it.
Check yourself
Question 1 / 8
0 answered
What does await mean?
Sources
- Owner
- Panaversity