Exercise: Pizza Order Tracker
Write the order tracker for a busy pizza shop with async and await, Promise.all and Promise.any, from one order through the oven to the fastest free driver, and let the tests check each piece.
Journeyman · JavaScript · Updated
It's Friday night at Pie in the Sky Pizza. The kitchen's code is written: making the dough, adding the toppings and baking each take a few minutes, and each one returns a promise. Sometimes a promise is rejected, because the shop has run out of mushrooms or a driver is busy. What the shop doesn't have yet is a tracker: something that follows an order from dough to oven, cooks a whole table's pizzas at the same time, and finds the fastest free driver. That's three functions for you to write, and tests check every one as you go.
Get the exercise code
In the Exercise box beside the lesson, choose Get the starter on GitHub to open its GitHub repository. Click Code, then Download ZIP, and unzip it where you keep your practice folders. Or clone it with Git.
The folder holds:
tracker.js: the three functions, for you to finish.kitchen.js: the kitchen. Its functionsmakeDough,addToppings,bakeandaskDrivereach return a promise, and the comments say what each one fulfills with and when it rejects. Ready to use: read it, but don't change it.track.js: runs a Friday-night rush with your functions and prints what happens. Ready to use.tracker.test.js: the tests that check your functions. You don't need to change it.package.json: tells Node.js how to run the code and its tests. Ready to use.
Everything runs in Node.js; there's no web page in this one. Open the folder in VS Code, and open a terminal there with Terminal > New Terminal.
What to do
Every function in tracker.js is already declared, with its parameters, and returns a placeholder for now. The comment above each one says what it should return, with examples:
// 1. trackOrder(order)
// Follow one order through the kitchen: makeDough, then addToppings, then bake. Each step needs the pizza
// the step before it gave back, so wait for each one before starting the next.
// Write it as an async function, with await, and with try and catch.
// When the pizza is baked, return 'Order <id>: <pizza> is ready'.
// When a step fails, return 'Order <id>: sorry, <the error's message>'. Never let the error escape.
// await trackOrder({ id: 101, pizza: 'Margherita', toppings: ['basil'] })
// -> 'Order 101: Margherita is ready'
// await trackOrder({ id: 102, pizza: 'Forest Mushroom', toppings: ['mushrooms', 'thyme'] })
// -> 'Order 102: sorry, out of mushrooms'
export function trackOrder(order) {
return '';
}
- Read
kitchen.js. Find out what each kitchen function fulfills with, what it needs to be given, and when it rejects. - Finish
trackOrder. Make it anasyncfunction. Wait for each kitchen step withawait, handing each one the pizza the step before it gave back, and catch a failure withtryandcatch, so the customer hears "sorry" instead of the program stopping. - Finish
orderForTheTable. A table orders several pizzas at once. Track every order at the same time withPromise.all, and return the lines in the same order as the orders. - Finish
fastestDelivery. Phone every driver at once withaskDriver, and take the first one who says yes, withPromise.any. When nobody can take it, return'No drivers free right now'.
Check your work
Run the tests from the terminal:
node --test
At first all 7 tests fail. That's expected: each function you finish turns its tests green. When a test fails, its message says what it expected, for example Return 'Order <id>: sorry, ' followed by the error's message. One test times the table's order: four pizzas cooked at the same time take about as long as one, and four cooked one after another take four times as long.
To watch your tracker run a Friday-night rush, run:
node track.js
Hints
- Follow the pizza.
makeDoughfulfills with a pizza object, andaddToppingsneeds that object, not the original order. Keep each step's result in its own variable withawait, as in async and await. - One try for all three steps. A single
tryaround the threeawaitlines catches a failure from any of them. Thecatchgets the error, and itsmessageis what the customer needs to hear. - Reuse what you've written.
orderForTheTablecan call yourtrackOrderonce for each order. Calling it starts the order right away;Promise.allonly does the waiting (see Waiting for Several Things at Once). - Why doesn't Promise.all give up here?
Promise.allis all or nothing, but yourtrackOrdercatches its own errors, so its promise is never rejected. A mushroom order comes back as a "sorry" line, and the rest of the table still gets their pizzas. - race or any? The busy driver answers first, to say no. Ask yourself which of the two waits for the first yes.
When you're done
All 7 tests are green, and node track.js prints:
One order, start to finish:
Order 101: Margherita is ready
A table for four:
Order 101: Margherita is ready
Order 102: sorry, out of mushrooms
Order 103: Pepperoni is ready
Order 104: Garden Veggie is ready
Who can take it?
Priya will deliver in 12 minutes
No drivers free right now
Now look back at your code. What would change if the shop decided that one failed pizza should cancel the whole table's order? Which of the four Promise tools would you use then?
So what
Waiting on slow work, one step after another, many at once, or the first that works, with a kind message when something fails: that's the heart of every app that talks to a server, from a food-delivery app's order screen to a game's online leaderboard. Next chapter, the slow work is real: data from the internet with fetch.