Skip to content

Commit b4c513b

Browse files
committed
feat(learn): add article on promises
1 parent 52f32bb commit b4c513b

File tree

3 files changed

+269
-0
lines changed

3 files changed

+269
-0
lines changed

apps/site/navigation.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@
244244
"link": "/learn/asynchronous-work/javascript-asynchronous-programming-and-callbacks",
245245
"label": "components.navigation.learn.asynchronousWork.links.javascriptAsynchronousProgrammingAndCallbacks"
246246
},
247+
"promisesInNodejs": {
248+
"link": "/learn/asynchronous-work/promises-in-nodejs",
249+
"label": "components.navigation.learn.asynchronousWork.links.promisesInNodejs"
250+
},
247251
"discoverJavascriptTimers": {
248252
"link": "/learn/asynchronous-work/discover-javascript-timers",
249253
"label": "components.navigation.learn.asynchronousWork.links.discoverJavascriptTimers"
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
---
2+
title: Promises in Node.js
3+
layout: learn
4+
authors: avivkeller
5+
---
6+
7+
# Promises in Node.js
8+
9+
A **Promise** is a special object in JavaScript that represents the eventual completion (or failure) of an asynchronous operation and its resulting value. Think of a Promise as a placeholder for a value that is not yet available but will be in the future.
10+
11+
Think of a Promise like ordering a pizza: you don't get it right away, but the delivery person promises to bring it to you later. You don't know _exactly_ when, but you know the outcome will either be "pizza delivered" or "something went wrong."
12+
13+
## Promise States
14+
15+
A Promise can be in one of three states:
16+
17+
- **Pending**: The initial state, where the asynchronous operation is still running.
18+
- **Fulfilled**: The operation completed successfully, and the Promise is now resolved with a value.
19+
- **Rejected**: The operation failed, and the Promise is settled with a reason (usually an error).
20+
21+
For example, imagine you're waiting for an email from a friend. You're in the pending state. If your friend replies, you've entered the fulfilled state. If the email bounces back, you are in the rejected state.
22+
23+
## Basic Syntax of a Promise
24+
25+
A Promise is created using the `new Promise()` constructor. The constructor takes a function with two parameters: `resolve` and `reject`. These functions are used to transition the Promise from the **pending** state to either **fulfilled** or **rejected**.
26+
27+
```js
28+
const myPromise = new Promise((resolve, reject) => {
29+
let success = true;
30+
31+
if (success) {
32+
resolve('Operation was successful!');
33+
} else {
34+
reject('Something went wrong.');
35+
}
36+
});
37+
```
38+
39+
In the above example:
40+
41+
- If the `success` condition is `true`, the Promise is fulfilled and the value `'Operation was successful!'` is passed to the `resolve` function.
42+
- If the `success` condition is `false`, the Promise is rejected and the error `'Something went wrong.'` is passed to the `reject` function.
43+
44+
## Handling Promises with `.then()` and `.catch()`
45+
46+
Once a Promise is created, you can handle the outcome by using the `.then()` and `.catch()` methods.
47+
48+
- `.then()` is used to handle a fulfilled Promise and access its result.
49+
- `.catch()` is used to handle a rejected Promise and catch any errors that may occur.
50+
51+
```js
52+
const myPromise = new Promise((resolve, reject) => {
53+
let success = true;
54+
55+
if (success) {
56+
resolve('Operation was successful!');
57+
} else {
58+
reject('Something went wrong.');
59+
}
60+
});
61+
62+
myPromise
63+
.then(result => {
64+
console.log(result); // This will run if the Promise is fulfilled
65+
})
66+
.catch(error => {
67+
console.error(error); // This will run if the Promise is rejected
68+
});
69+
```
70+
71+
## Chaining Promises
72+
73+
One of the great features of Promises is that they allow you to chain multiple asynchronous operations together. When you chain Promises, each `.then()` block waits for the previous one to complete before it runs.
74+
75+
```js
76+
const promise1 = new Promise((resolve, reject) => {
77+
setTimeout(() => resolve('First task completed'), 1000);
78+
});
79+
80+
const promise2 = new Promise((resolve, reject) => {
81+
setTimeout(() => resolve('Second task completed'), 1000);
82+
});
83+
84+
promise1
85+
.then(result => {
86+
console.log(result); // 'First task completed'
87+
return promise2; // Return the second Promise
88+
})
89+
.then(result => {
90+
console.log(result); // 'Second task completed'
91+
})
92+
.catch(error => {
93+
console.error(error); // If any Promise is rejected, catch the error
94+
});
95+
```
96+
97+
In this example:
98+
99+
- The first Promise resolves after 1 second, and its result is logged.
100+
- The second Promise resolves after another second, and its result is logged after the first one finishes.
101+
102+
## Using Async/Await with Promises
103+
104+
One of the best ways to work with Promises in modern JavaScript is using **async/await**. This allows you to write asynchronous code that looks synchronous, making it much easier to read and maintain.
105+
106+
- `async` is used to define a function that returns a Promise.
107+
- `await` is used inside an `async` function to pause execution until the Promise is resolved or rejected.
108+
109+
```js
110+
async function performTasks() {
111+
try {
112+
const result1 = await promise1;
113+
console.log(result1); // 'First task completed'
114+
115+
const result2 = await promise2;
116+
console.log(result2); // 'Second task completed'
117+
} catch (error) {
118+
console.error(error); // Catches any rejection or error
119+
}
120+
}
121+
122+
performTasks();
123+
```
124+
125+
In the `performTasks` function, the `await` keyword pauses execution until each Promise is settled (resolved or rejected). This leads to a more linear and readable flow of asynchronous code.
126+
127+
## Promise-based Node.js APIs
128+
129+
Node.js provides **Promise-based versions** of many of its core APIs, especially in cases where asynchronous operations were traditionally handled with callbacks. This makes it easier to work with Node.js APIs and Promises, and reduces the risk of "callback hell."
130+
131+
For example, the `fs` (file system) module has a Promise-based API under `fs.promises`:
132+
133+
```js
134+
const fs = require('node:fs').promises;
135+
// Or, you can import the promisified version directly:
136+
// const fs = require('node:fs/promises');
137+
138+
async function readFile() {
139+
try {
140+
const data = await fs.readFile('example.txt', 'utf8');
141+
console.log(data);
142+
} catch (err) {
143+
console.error('Error reading file:', err);
144+
}
145+
}
146+
147+
readFile();
148+
```
149+
150+
In this example, `fs.promises.readFile()` returns a Promise, which we handle using `async/await` syntax to read the contents of a file asynchronously.
151+
152+
## Advanced Promise Methods
153+
154+
JavaScript's `Promise` global provides several powerful methods that help manage multiple asynchronous tasks more effectively:
155+
156+
### **`Promise.all()`**:
157+
158+
This method takes an array of Promises and resolves them all. It only resolves when all Promises are fulfilled. If any of the Promises is rejected, `Promise.all()` will reject immediately.
159+
160+
```js
161+
const fetchData1 = new Promise(resolve =>
162+
setTimeout(() => resolve('Data from API 1'), 1000)
163+
);
164+
const fetchData2 = new Promise(resolve =>
165+
setTimeout(() => resolve('Data from API 2'), 2000)
166+
);
167+
168+
Promise.all([fetchData1, fetchData2])
169+
.then(results => {
170+
console.log(results); // ['Data from API 1', 'Data from API 2']
171+
})
172+
.catch(error => {
173+
console.error('Error:', error);
174+
});
175+
```
176+
177+
### **`Promise.allSettled()`**:
178+
179+
This method waits for all promises to either resolve or reject and returns an array of objects that describe the outcome of each Promise.
180+
181+
```js
182+
const promise1 = Promise.resolve('Success');
183+
const promise2 = Promise.reject('Failed');
184+
185+
Promise.allSettled([promise1, promise2]).then(results => {
186+
console.log(results);
187+
// [ { status: 'fulfilled', value: 'Success' }, { status: 'rejected', reason: 'Failed' } ]
188+
});
189+
```
190+
191+
### **`Promise.race()`**:
192+
193+
This method resolves or rejects as soon as the first Promise settles, whether it resolves or rejects.
194+
195+
```js
196+
const task1 = new Promise(resolve =>
197+
setTimeout(() => resolve('Task 1 done'), 2000)
198+
);
199+
const task2 = new Promise(resolve =>
200+
setTimeout(() => resolve('Task 2 done'), 1000)
201+
);
202+
203+
Promise.race([task1, task2]).then(result => {
204+
console.log(result); // 'Task 2 done' (since task2 finishes first)
205+
});
206+
```
207+
208+
### **`Promise.any()`**:
209+
210+
This method resolves as soon as one of the Promises resolves. If all promises are rejected, it will reject with an `AggregateError`.
211+
212+
```js
213+
const api1 = new Promise((_, reject) =>
214+
setTimeout(() => reject('API 1 failed'), 1000)
215+
);
216+
const api2 = new Promise(resolve =>
217+
setTimeout(() => resolve('API 2 success'), 500)
218+
);
219+
220+
Promise.any([api1, api2])
221+
.then(result => {
222+
console.log(result); // 'API 2 success' (since it resolves first)
223+
})
224+
.catch(error => {
225+
console.error('All promises rejected:', error);
226+
});
227+
```
228+
229+
### **`Promise.reject()` and `Promise.resolve()`**:
230+
231+
These methods create a rejected or resolved Promise directly.
232+
233+
```js
234+
Promise.resolve('Resolved immediately').then(result => {
235+
console.log(result); // 'Resolved immediately'
236+
});
237+
```
238+
239+
## Error Handling with Promises
240+
241+
Handling errors in Promises ensures your application behaves correctly in case of unexpected situations.
242+
243+
- You can use `.catch()` to handle any errors or rejections that occur during the execution of Promises.
244+
245+
```js
246+
myPromise
247+
.then(result => console.log(result))
248+
.catch(error => console.error(error)); // Handles the rejection
249+
```
250+
251+
- Alternatively, when using `async/await`, you can use a `try/catch` block to catch and handle errors.
252+
253+
```js
254+
async function performTask() {
255+
try {
256+
const result = await myPromise;
257+
console.log(result);
258+
} catch (error) {
259+
console.error(error); // Handles any errors
260+
}
261+
}
262+
263+
performTask();
264+
```

packages/i18n/locales/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"links": {
6262
"asynchronousWork": "Asynchronous Work",
6363
"asynchronousFlowControl": "Asynchronous flow control",
64+
"promisesInNodejs": "Promises in Node.js",
6465
"overviewOfBlockingVsNonBlocking": "Overview of Blocking vs Non-Blocking",
6566
"javascriptAsynchronousProgrammingAndCallbacks": "JavaScript Asynchronous Programming and Callbacks",
6667
"discoverJavascriptTimers": "Discover JavaScript Timers",

0 commit comments

Comments
 (0)