Using Promises and Async/Await Effectively in Node.js
Dive into the best use cases for promises and async/await patterns to handle asynchronous operations smoothly.
0 likes
3 views
Rule Content
--- description: Enforce the use of async/await over callbacks and Promises for handling asynchronous operations in Node.js to improve code readability and maintainability. globs: src/**/*.js tags: [Node.js, async/await, coding standards] priority: 2 version: 1.0.0 --- # Using Promises and Async/Await Effectively in Node.js ## Context - Applicable to all Node.js projects handling asynchronous operations. - Requires Node.js version 8 or higher. ## Requirements - **Use async/await for asynchronous operations**: Replace callbacks and Promise chains with async/await syntax to enhance code clarity and reduce nesting. - **Implement proper error handling**: Utilize try/catch blocks within async functions to manage errors effectively. - **Avoid mixing callbacks and Promises**: Convert callback-based functions to return Promises, enabling the use of async/await throughout the codebase. - **Prevent unhandled Promise rejections**: Ensure all Promises are awaited or have catch handlers to handle potential errors. - **Optimize asynchronous loops**: Use Promise.all() for parallel execution instead of awaiting each operation sequentially within loops. ## Examples <example> // Good: Using async/await with proper error handling async function fetchData() { try { const data = await getData(); console.log(data); } catch (error) { console.error('Error fetching data:', error); } } </example> <example type="invalid"> // Bad: Using callbacks leading to callback hell getData(function(error, data) { if (error) { console.error('Error fetching data:', error); } else { processData(data, function(error, processedData) { if (error) { console.error('Error processing data:', error); } else { saveData(processedData, function(error) { if (error) { console.error('Error saving data:', error); } else { console.log('Data saved successfully'); } }); } }); } }); </example> <example> // Good: Converting a callback-based function to return a Promise const fs = require('fs').promises; async function readFileAsync(filePath) { try { const data = await fs.readFile(filePath, 'utf8'); return data; } catch (error) { throw new Error('Error reading file:', error); } } </example> <example type="invalid"> // Bad: Mixing callbacks and Promises const fs = require('fs'); function readFileAsync(filePath) { return new Promise((resolve, reject) => { fs.readFile(filePath, 'utf8', (error, data) => { if (error) { reject(error); } else { resolve(data); } }); }); } readFileAsync('example.txt', (error, data) => { if (error) { console.error('Error reading file:', error); } else { console.log(data); } }); </example> <example> // Good: Using Promise.all() for parallel execution async function fetchMultipleData(urls) { try { const fetchPromises = urls.map(url => fetch(url)); const responses = await Promise.all(fetchPromises); const data = await Promise.all(responses.map(response => response.json())); return data; } catch (error) { console.error('Error fetching data:', error); } } </example> <example type="invalid"> // Bad: Awaiting each operation sequentially within a loop async function fetchMultipleData(urls) { const data = []; for (const url of urls) { try { const response = await fetch(url); const jsonData = await response.json(); data.push(jsonData); } catch (error) { console.error('Error fetching data from', url, ':', error); } } return data; } </example>