In previous exercises we learned about callbacks and Promises. Now it is time to learn about
async/await — syntax introduced in ES2017 that makes asynchronous code look and behave almost like synchronous code.In Jurassic Park, imagine you are a scientist who needs to: collect a DNA sample, sequence it, synthesize a protein, grow cells, and finally create a dinosaur. With
async/await this process reads like a straightforward step-by-step procedure, even though each step is asynchronous!Placing
async before a function declaration makes it an async function. An async function:return a plain value)await keyword inside its body1// Regular function — returns undefined
2function getName() {
3 return "Rexy";
4}
5
6// Async function — returns Promise<string>
7async function getDinosaurName() {
8 return "Rexy"; // Automatically wrapped in Promise.resolve("Rexy")
9}
10
11getName(); // "Rexy"
12getDinosaurName(); // Promise { 'Rexy' }
13getDinosaurName().then(name => console.log(name)); // "Rexy"await can only be used inside an async function. It pauses execution of the async function until the Promise settles, then resumes with the resolved value.1function fetchDinosaurData(id) {
2 return new Promise(resolve => {
3 setTimeout(() => resolve({ id, name: "Blue", species: "Velociraptor", health: 98 }), 1000);
4 });
5}
6
7// Without async/await — using .then()
8function showDinoInfoOld(id) {
9 return fetchDinosaurData(id).then(dino => {
10 console.log(`${dino.name} (${dino.species}) — health: ${dino.health}%`);
11 return dino;
12 });
13}
14
15// With async/await — reads like synchronous code
16async function showDinoInfo(id) {
17 const dino = await fetchDinosaurData(id); // Pauses here until Promise resolves
18 console.log(`${dino.name} (${dino.species}) — health: ${dino.health}%`);
19 return dino;
20}
21
22showDinoInfo(1);Let's compare the same functionality implemented with traditional Promise syntax and async/await:
1// Using traditional Promises
2function checkSecuritySystems() {
3 console.log("Checking security systems...");
4
5 return fetchGateStatus()
6 .then(gateStatus => {
7 console.log("Gate status:", gateStatus.allClosed ? "All closed" : "WARNING! Some are open");
8
9 return fetchFenceStatus();
10 })
11 .then(fenceStatus => {
12 console.log("Fence:", fenceStatus.power > 8000 ? "Secured" : "Insufficient power!");
13
14 return fetchCameraStatus();
15 })
16 .then(cameraStatus => {
17 console.log("Cameras:", cameraStatus.allOperational ? "All operational" : "Some are not working!");
18
19 return {
20 gate: gateStatus,
21 fence: fenceStatus,
22 cameras: cameraStatus,
23 checkDuration: new Date().toISOString()
24 };
25 })
26 .catch(error => {
27 console.error("Error during check:", error.message);
28 throw new Error(`Check failed: ${error.message}`);
29 });
30}
31
32// Using async/await
33async function checkSecuritySystems() {
34 console.log("Checking security systems...");
35
36 try {
37 // Each of the following calls pauses function execution
38 const gateStatus = await fetchGateStatus();
39 console.log("Gate status:", gateStatus.allClosed ? "All closed" : "WARNING! Some are open");
40
41 const fenceStatus = await fetchFenceStatus();
42 console.log("Fence:", fenceStatus.power > 8000 ? "Secured" : "Insufficient power!");
43
44 const cameraStatus = await fetchCameraStatus();
45 console.log("Cameras:", cameraStatus.allOperational ? "All operational" : "Some are not working!");
46
47 return {
48 gate: gateStatus,
49 fence: fenceStatus,
50 cameras: cameraStatus,
51 checkDuration: new Date().toISOString()
52 };
53 } catch (error) {
54 console.error("Error during check:", error.message);
55 throw new Error(`Check failed: ${error.message}`);
56 }
57}Notice that:
gateStatus, fenceStatus, cameraStatus)try/catch syntax instead of .catch()Any function that returns a Promise can be transformed into an async function:
1// Function returning a Promise
2function measureEnclosureTemperature(enclosureId) {
3 return new Promise((resolve, reject) => {
4 // Measurement code...
5 });
6}
7
8// Transformed to async function
9async function measureEnclosureTemperature(enclosureId) {
10 // We can use asynchronous operations with await
11 const sensor = await connectToSensor(enclosureId);
12 const reading = await sensor.getTemperature();
13
14 if (reading.status === "error") {
15 throw new Error(`Temperature reading error: ${reading.message}`);
16 }
17
18 return {
19 enclosureId,
20 temperature: reading.value,
21 unit: "Celsius",
22 measurementTime: new Date()
23 };
24}Instead of
.catch(), async functions use regular try/catch:1async function performHealthCheck(dinoId) {
2 try {
3 const dino = await fetchDinosaurData(dinoId);
4 const enclosure = await fetchEnclosureStatus(dino.enclosureId);
5 const vetReport = await fetchVetReport(dinoId);
6
7 return {
8 dinosaur: dino.name,
9 enclosureOk: enclosure.status === "secure",
10 lastCheckup: vetReport.date,
11 overall: "healthy"
12 };
13 } catch (error) {
14 console.error(`Health check failed for dinosaur ${dinoId}: ${error.message}`);
15 return { dinosaur: dinoId, overall: "unknown", error: error.message };
16 } finally {
17 console.log(`Health check routine complete for dinosaur ${dinoId}`);
18 }
19}
20
21// Stub functions
22function fetchEnclosureStatus(id) {
23 return Promise.resolve({ id, status: "secure", lastInspected: "2024-01-15" });
24}
25function fetchVetReport(id) {
26 return Promise.resolve({ dinoId: id, date: "2024-01-10", notes: "All clear" });
27}
28
29performHealthCheck(42).then(report => console.log(report));1async function releaseDinosaurFromEnclosure(dinoId, enclosureId) {
2 try {
3 // Check if we have permissions
4 const permissions = await checkPermissions();
5 if (!permissions.canReleaseAnimals) {
6 throw new Error("No permission to release dinosaurs");
7 }
8
9 // Check dinosaur status
10 const dinosaurStatus = await checkDinosaurStatus(dinoId);
11 if (dinosaurStatus.health !== "Good") {
12 throw new Error(`Dinosaur #${dinoId} nie jest w dobrym stanie zdrowia`);
13 }
14
15 // Check if the enclosure is secure
16 const enclosureStatus = await checkEnclosureStatus(enclosureId);
17 if (!enclosureStatus.isSecure) {
18 throw new Error(`Wybieg #${enclosureId} nie jest bezpieczny`);
19 }
20
21 // Open the enclosure gate
22 await openEnclosureGateById(enclosureId);
23 console.log(`Brama enclosureu #${enclosureId} otwarta`);
24
25 // Release the dinosaur
26 const result = await transferDinosaur(dinoId, enclosureId, "outdoor-area");
27 console.log(`Dinosaur #${dinoId} has been released to the outdoor area of enclosure #${enclosureId}`);
28
29 return {
30 success: true,
31 message: `Dinosaur #${dinoId} has been successfully released`,
32 details: result
33 };
34 } catch (error) {
35 console.error("Dinosaur release operation failed:", error.message);
36
37 // We can attempt to fix the error or perform cleanup operations
38 try {
39 await closeAllGates();
40 await activateSecuritySystem();
41 } catch (cleanupError) {
42 console.error("Error during cleanup operations:", cleanupError.message);
43 }
44
45 return {
46 success: false,
47 message: `Error while releasing dinosaur: ${error.message}`,
48 error: error.message
49 };
50 }
51}In the above example we used a
try/catch block to handle any errors that may occur during the dinosaur release process. We can also nest try/catch blocks, as seen in the error handler where we attempt cleanup operations that may also fail.The introduction of async/await also enabled asynchronous iterations, which are particularly useful when working with collections of objects that require asynchronous operations.
1async function examineAllDinosaurs(idList) {
2 console.log(`Starting examination of ${idList.length} dinosaurs...`);
3
4 const results = [];
5
6 // Sequential processing (one after another)
7 for (const id of idList) {
8 try {
9 const result = await examineDinosaur(id);
10 console.log(`Dinosaur #${id} przebadany: ${result.status}`);
11 results.push({
12 id,
13 success: true,
14 result: result
15 });
16 } catch (error) {
17 console.error(`Error examining dinosaur #${id}: ${error.message}`);
18 results.push({
19 id,
20 success: false,
21 error: error.message
22 });
23 }
24 }
25
26 return {
27 totalExaminations: idList.length,
28 successful: results.filter(w => w.success).length,
29 niesuccessful: results.filter(w => !w.success).length,
30 results
31 };
32}In the above example we use
for...of with await inside the loop, which causes dinosaur examinations to be performed one after another. This is the appropriate approach when order matters or when operations must be performed sequentially.If operations don't need to be performed sequentially, it's often better to process the collection in parallel:
1async function examineAllDinosaursInParallel(idList) {
2 console.log(`Starting examination of ${idList.length} dinosaurs in parallel...`);
3
4 // Creating an array of promises
5 const promises = idList.map(id => {
6 return examineDinosaur(id)
7 .then(result => ({
8 id,
9 success: true,
10 result: result
11 }))
12 .catch(error => ({
13 id,
14 success: false,
15 error: error.message
16 }));
17 });
18
19 // Parallel execution of all examinations
20 const results = await Promise.all(promises);
21
22 return {
23 totalExaminations: idList.length,
24 successful: results.filter(w => w.success).length,
25 niesuccessful: results.filter(w => !w.success).length,
26 results
27 };
28}In this case we use
map() to create an array of Promises and then use Promise.all() with await to wait for all operations to complete. This way all examinations are performed in parallel, which can significantly speed up the processing of large collections.Sometimes we don't want to perform all operations simultaneously as that could overload the system. In such cases we can limit the number of parallel operations:
1async function examineDinosaursWithLimit(idList, maxParallel = 3) {
2 console.log(`Starting examination of ${idList.length} dinosaurs (max ${maxParallel} in parallel)...`);
3
4 const results = [];
5
6 // Processing in batches
7 for (let i = 0; i < idList.length; i += maxParallel) {
8 const batch = idList.slice(i, i + maxParallel);
9 console.log(`Processing batch ${Math.floor(i / maxParallel) + 1} (${batch.length} dinosaurs)...`);
10
11 // Creating promise array for the current batch
12 const promisesPorcji = batch.map(id => {
13 return examineDinosaur(id)
14 .then(result => ({
15 id,
16 success: true,
17 result: result
18 }))
19 .catch(error => ({
20 id,
21 success: false,
22 error: error.message
23 }));
24 });
25
26 // Parallel execution of examinations in the current batch
27 const resultsPorcji = await Promise.all(promisesPorcji);
28 results.push(...resultsPorcji);
29
30 console.log(`Batch ${Math.floor(i / maxParallel) + 1} completed.`);
31 }
32
33 return {
34 totalExaminations: idList.length,
35 successful: results.filter(w => w.success).length,
36 niesuccessful: results.filter(w => !w.success).length,
37 results
38 };
39}In this case we process the ID list in batches of
maxParallel elements. Each batch is processed in parallel, but we wait for all operations in one batch to complete before moving to the next.One of the most important concepts with async/await is knowing when execution is sequential and when it is parallel:
1// SEQUENTIAL — each awaits before the next starts
2async function sequentialCheck() {
3 console.time("sequential");
4 const fence = await checkFenceSystem("A"); // ~1 second
5 const camera = await checkCameraSystem("North"); // ~1 second
6 const sensor = await checkMotionSensors("B"); // ~1 second
7 console.timeEnd("sequential"); // ~3 seconds total
8 return [fence, camera, sensor];
9}
10
11// PARALLEL — all start at the same time, await all results
12async function parallelCheck() {
13 console.time("parallel");
14 const [fence, camera, sensor] = await Promise.all([
15 checkFenceSystem("A"),
16 checkCameraSystem("North"),
17 checkMotionSensors("B")
18 ]);
19 console.timeEnd("parallel"); // ~1 second total
20 return [fence, camera, sensor];
21}
22
23// Stub functions
24function checkFenceSystem(id) { return new Promise(res => setTimeout(() => res({ sector: id, ok: true }), 800)); }
25function checkCameraSystem(id) { return new Promise(res => setTimeout(() => res({ zone: id, ok: true }), 900)); }
26function checkMotionSensors(id) { return new Promise(res => setTimeout(() => res({ area: id, ok: true }), 700)); }Rule of thumb:
await one-by-one only when each operation depends on the result of the previous onePromise.all() with await when operations are independent — it is much faster1async function prepareDinoReport(dinoId) {
2 // Step 1: Must happen first (ID needed for step 2)
3 const dino = await fetchDinosaurData(dinoId);
4
5 // Steps 2-4 are independent of each other — run in parallel
6 const [enclosure, vetRecord, feedingLog] = await Promise.all([
7 fetchEnclosureStatus(dino.enclosureId),
8 fetchVetReport(dino.id),
9 fetchFeedingLog(dino.id)
10 ]);
11
12 return { dino, enclosure, vetRecord, feedingLog };
13}
14
15function fetchFeedingLog(id) {
16 return Promise.resolve({ dinoId: id, lastFed: "2024-01-15 08:00", amount: "50kg" });
17}async works with all function forms:1// Async arrow function
2const getDinoStatus = async (id) => {
3 const data = await fetchDinosaurData(id);
4 return data.health > 80 ? "healthy" : "needs attention";
5};
6
7// Async class method
8class DinoMonitor {
9 constructor(parkId) {
10 this.parkId = parkId;
11 }
12
13 async runFullScan() {
14 console.log(`Starting full scan of park ${this.parkId}...`);
15 const results = await Promise.all([
16 this.checkAllFences(),
17 this.checkAllCameras()
18 ]);
19 return results;
20 }
21
22 async checkAllFences() {
23 // Simulate checking fences
24 await new Promise(res => setTimeout(res, 600));
25 return { fences: "all secure", checked: 24 };
26 }
27
28 async checkAllCameras() {
29 await new Promise(res => setTimeout(res, 400));
30 return { cameras: "all online", checked: 48 };
31 }
32}
33
34const monitor = new DinoMonitor("JP-001");
35monitor.runFullScan().then(results => console.log("Scan results:", results));1class DinosaurMonitoringSystem {
2 constructor(sector) {
3 this.sector = sector;
4 this.active = false;
5 this.dinosaurs = [];
6 }
7
8 async initialize() {
9 try {
10 // Fetch dinosaur list in the sector
11 const lista = await fetchDinosaurListInSector(this.sector);
12 this.dinosaurs = lista;
13
14 // Initialize sensors
15 await this.initializeCzujniki();
16
17 this.active = true;
18 console.log(`System monitorowania sectora ${this.sector} zainicjalizowany`);
19
20 return true;
21 } catch (error) {
22 console.error(`Monitoring system initialization error: ${error.message}`);
23 return false;
24 }
25 }
26
27 async initializeCzujniki() {
28 // Initialize sensors for each dinosaur
29 const promises = this.dinosaurs.map(dino =>
30 initializeCzujnikDlaDinosaura(dino.id)
31 );
32
33 return Promise.all(promises);
34 }
35
36 async monitor(monitoringDuration = 60000) {
37 if (!this.active) {
38 throw new Error("System monitorowania nie jest active");
39 }
40
41 console.log(`Rozpoczynam monitorowanie sectora ${this.sector} for ${monitoringDuration/1000} sekund...`);
42
43 // Monitor for a specified time
44 const startTime = Date.now();
45
46 while (Date.now() - startTime < monitoringDuration) {
47 // Fetch status of all dinosaurs
48 const statuses = await Promise.all(
49 this.dinosaurs.map(dino => checkDinosaurStatus(dino.id))
50 );
51
52 // Analyze statuses
53 const abnormalDinosaurs = statuses.filter(s => s.status !== "normal");
54
55 if (abnormalDinosaurs.length > 0) {
56 console.warn(`Detected ${abnormalDinosaurs.length} dinosaurs with abnormal status!`);
57
58 for (const status of abnormalDinosaurs) {
59 console.warn(`Dinosaur #${status.dinoId}: ${status.status} - ${status.details}`);
60
61 // Send alert for each abnormal status
62 await sendAlert(this.sector, status);
63 }
64 }
65
66 // Wait 5 seconds before the next check
67 await new Promise(resolve => setTimeout(resolve, 5000));
68 }
69
70 console.log(`Monitoring of sector ${this.sector} completed.`);
71 return `Monitoring completed: ${new Date().toISOString()}`;
72 }
73}
74
75// Using the class
76async function startMonitoringSystem(sector) {
77 const system = new DinosaurMonitoringSystem(sector);
78
79 const initializationSuccessful = await system.initialize();
80 if (!initializationSuccessful) {
81 console.error(`Failed to initialize the system for sector ${sector}`);
82 return;
83 }
84
85 // Monitor for 5 minutes
86 await system.monitor(300000);
87
88 console.log(`Monitoring session for sector ${sector} completed`);
89}Sometimes you need to run async code at the top level (outside any async function). Use an async IIFE:
1// Immediately runs the async function
2(async () => {
3 try {
4 const status = await getDinoStatus(7);
5 console.log("Status:", status);
6
7 const report = await prepareDinoReport(7);
8 console.log("Report ready for dinosaur:", report.dino.name);
9 } catch (error) {
10 console.error("Top-level error:", error.message);
11 }
12})();Async functions can call themselves recursively:
1async function retryOperation(operation, maxRetries, delay = 500) {
2 for (let attempt = 1; attempt <= maxRetries; attempt++) {
3 try {
4 const result = await operation();
5 console.log(`Success on attempt ${attempt}`);
6 return result;
7 } catch (error) {
8 console.log(`Attempt ${attempt} failed: ${error.message}`);
9 if (attempt === maxRetries) throw error;
10 await new Promise(res => setTimeout(res, delay * attempt)); // Exponential-ish backoff
11 }
12 }
13}
14
15// Usage — retry sensor read up to 3 times
16async function readUnreliableSensor(sensorId) {
17 return retryOperation(
18 () => new Promise((resolve, reject) => {
19 setTimeout(() => {
20 Math.random() > 0.6
21 ? resolve({ sensorId, value: Math.random() * 100 })
22 : reject(new Error(`Sensor ${sensorId} did not respond`));
23 }, 300);
24 }),
25 3 // Max 3 attempts
26 );
27}
28
29readUnreliableSensor("THERMO-07")
30 .then(data => console.log("Final reading:", data.value.toFixed(1)))
31 .catch(error => console.error("All retries failed:", error.message));Async generators combine generators with async operations — perfect for streaming data:
1async function* streamDinoUpdates(dinoIds, intervalMs) {
2 for (const id of dinoIds) {
3 // Simulate fetching live update for each dinosaur
4 await new Promise(res => setTimeout(res, intervalMs));
5 const update = await fetchDinosaurData(id);
6 yield { timestamp: new Date().toISOString(), dinosaur: update };
7 }
8}
9
10// Consuming the async generator
11async function monitorLive() {
12 const generator = streamDinoUpdates([1, 2, 3, 4, 5], 500);
13
14 for await (const update of generator) {
15 console.log(`[${update.timestamp}] ${update.dinosaur.name}: health ${update.dinosaur.health}%`);
16 }
17
18 console.log("Live monitoring cycle complete.");
19}
20
21monitorLive();1// ❌ Mistake 1: Using await without async
2function badFunction() {
3 const data = await fetchDinosaurData(1); // SyntaxError!
4}
5
6// ✅ Fix: Mark function as async
7async function goodFunction() {
8 const data = await fetchDinosaurData(1); // OK
9}
10
11// ❌ Mistake 2: Sequential awaits for independent operations (slow)
12async function slowReport(id) {
13 const a = await fetchDinosaurData(id);
14 const b = await fetchEnclosureStatus(a.enclosureId); // Only needs enclosureId
15 const c = await fetchVetReport(id); // Independent — but waits for b to finish!
16 return { a, b, c };
17}
18
19// ✅ Fix: Parallel where possible
20async function fastReport(id) {
21 const dino = await fetchDinosaurData(id);
22 const [enclosure, vetReport] = await Promise.all([
23 fetchEnclosureStatus(dino.enclosureId),
24 fetchVetReport(id) // Runs in parallel with enclosure fetch
25 ]);
26 return { dino, enclosure, vetReport };
27}
28
29// ❌ Mistake 3: Forgetting to await — fires and forgets
30async function badSave(data) {
31 saveToDatabase(data); // Not awaited — errors are silently swallowed!
32 console.log("Saved!"); // Prints before save completes
33}
34
35// ✅ Fix: Always await async operations whose result matters
36async function goodSave(data) {
37 await saveToDatabase(data);
38 console.log("Saved!");
39}
40
41function saveToDatabase(data) { return new Promise(res => setTimeout(res, 500)); }The async/await syntax opens new possibilities for design patterns in JavaScript. Here are a few useful patterns:
1async function withRetries(operation, options = {}) {
2 const { maxAttempts = 3, delay = 1000, backoffMultiplier = 2 } = options;
3
4 let lastError;
5
6 for (let attempt = 1; attempt <= maxAttempts; attempt++) {
7 try {
8 if (attempt > 1) {
9 console.log(`Attempt ${attempt}/${maxAttempts}...`);
10 }
11
12 return await operation();
13 } catch (error) {
14 console.error(`Attempt ${attempt} failed: ${error.message}`);
15 lastError = error;
16
17 if (attempt < maxAttempts) {
18 const waitTime = delay * Math.pow(backoffMultiplier, attempt - 1);
19 console.log(`Waiting ${waitTime}ms before the next attempt...`);
20 await new Promise(resolve => setTimeout(resolve, waitTime));
21 }
22 }
23 }
24
25 throw new Error(`Operation failed after ${maxAttempts} attempts. Last error: ${lastError.message}`);
26}
27
28// Example usage
29async function connectToSecuritySystem() {
30 return withRetries(
31 async () => {
32 const connection = await establishSecuritySystemConnection();
33 const autentykacja = await authenticateConnection(connection);
34 return await fetchSecurityStatus(connection, autentykacja);
35 },
36 {
37 maxAttempts: 5,
38 delay: 2000,
39 backoffMultiplier: 1.5
40 }
41 );
42}1async function withTimeout(operation, timeLimit, message) {
2 // Create a Promise that rejects after the time limit
3 const timeoutPromise = new Promise((_, reject) => {
4 setTimeout(() => {
5 reject(new Error(`Time limit exceeded (${timeLimit}ms): ${message}`));
6 }, timeLimit);
7 });
8
9 // Race between the operation and the timeout
10 return Promise.race([operation(), timeoutPromise]);
11}
12
13// Example usage
14async function safeTemperatureReading(enclosureId) {
15 try {
16 const temperatura = await withTimeout(
17 () => readEnclosureTemperature(enclosureId),
18 5000,
19 `Reading temperature of enclosure #${enclosureId}`
20 );
21
22 console.log(`Enclosure #${enclosureId}: ${temperatura}°C`);
23 return temperatura;
24 } catch (error) {
25 console.error(`Temperature reading error: ${error.message}`);
26 return null; // Or we can return a default value
27 }
28}1async function withExponentialBackoff(operation, options = {}) {
2 const {
3 maxAttempts = 5,
4 baseWait = 1000,
5 maxWait = 30000,
6 jitter = true
7 } = options;
8
9 let attempt = 0;
10
11 while (true) {
12 try {
13 return await operation(++attempt);
14 } catch (error) {
15 if (attempt >= maxAttempts) {
16 throw new Error(`Operation failed after ${attempt} attemptch: ${error.message}`);
17 }
18
19 // Calculate wait time with exponential backoff
20 let waitTime = Math.min(
21 maxWait,
22 baseWait * Math.pow(2, attempt - 1)
23 );
24
25 // Add jitter (randomness) to the wait time
26 if (jitter) {
27 waitTime = waitTime * (0.5 + Math.random() * 0.5);
28 }
29
30 console.log(`Attempt ${attempt} failed. Waiting ${Math.round(waitTime)}ms before the next attempt...`);
31
32 await new Promise(resolve => setTimeout(resolve, waitTime));
33 }
34 }
35}
36
37// Example usage
38async function synchronizeDataWithCentral() {
39 return withExponentialBackoff(
40 async (attempt) => {
41 console.log(`Attempt synchronizacji #${attempt}...`);
42 const data = await fetchCurrentData();
43 await sendDataToCentral(data);
44 return `Synchronization completed: ${data.length} records`;
45 },
46 {
47 maxAttempts: 10,
48 baseWait: 2000,
49 maxWait: 60000
50 }
51 );
52}1async function cascadeSearch(query) {
2 console.log(`Starting cascade search for: ${query}`);
3
4 // Try the cache first
5 try {
6 console.log("Searching cache...");
7 const cacheResult = await searchCache(query);
8 console.log("Found in cache!");
9 return {
10 source: "cache",
11 result: cacheResult
12 };
13 } catch (error) {
14 console.log("Not found in cache, trying local database...");
15 }
16
17 // Then try the local database
18 try {
19 const localResult = await searchLocalDatabase(query);
20 console.log("Found in local database!");
21 // Update cache
22 await updateCache(query, localResult);
23 return {
24 source: "local_db",
25 result: localResult
26 };
27 } catch (error) {
28 console.log("Not found in local database, trying central database...");
29 }
30
31 // Finally try the central database
32 try {
33 const centralResult = await searchCentralDatabase(query);
34 console.log("Found in central database!");
35 // Update local database and cache
36 await updateLocalDatabase(query, centralResult);
37 await updateCache(query, centralResult);
38 return {
39 source: "central_db",
40 result: centralResult
41 };
42 } catch (error) {
43 throw new Error(`No results found for query: ${query}`);
44 }
45}The async/await syntax offers an elegant and readable way of working with asynchronous code in JavaScript, built on top of Promises. Here are the main advantages:
try/catch syntax instead of .catch()However, keep a few important points in mind:
await inside the functionawait before each call causes sequential execution, which may not be optimaltry/catch or .catch() when calling async functionsIn Jurassic Park, as in any complex JavaScript application, async/await is an invaluable tool for managing asynchronous operations, such as communicating with security systems, monitoring dinosaurs, or coordinating various park subsystems.
In the next exercise we will focus on error handling strategies in asynchronous code, which is crucial for creating resilient and reliable applications.