If there are promises in the project, the whole code will work through them. Unfortunately, not all libraries have an interface for dealing with promises, so they operate the old-fashioned way, through callbacks. In such cases, we need to wrap functions or promise them.
To create promises, use the Promise
builder:
import fs from 'fs';
const promise = new Promise((resolve, reject) => {
fs.readFile('/etc/passwd', (err, data) => {
if (err) {
reject(err);
return;
}
resolve(data);
});
});
Promises expect that a function will be called when it is created. Within that function, we should execute the asynchronous operation on the callback, that we want to turn into a promise.
Promises throw two callbacks into this function:
resolve
- should be called if the asynchronous operation is completed successfully. As an input, it takes the result of the operationreject
- should be called in case of an error. As an input, it takes the error
These functions take exactly one argument, passed:
- To
then
, if there is some data - To
catch
, if there is an error
It's enough to call at least one of these functions. It may be necessary to create a promise that always ends successfully, and you can easily do this without ever calling reject
.
Finally, the new new Promise()
construct returns a real promise we can work with the way we're used to:
promise
.then(console.log)
.catch(console.log)
What if we have to wrap two asynchronous operations or more? We should wrap each of them independently.
In other words, one asynchronous operation means one constructor new Promise
. By the way, you can automate this task. There's a function built into node.js that makes promises out of asynchronous functions:
import util from 'util';
import fs from 'fs';
const stat = util.promisify(fs.stat);
stat('.').then((stats) => {
// Doing something with `stats`
}).catch((error) => {
// Handling the error
});
You can also do this in the front end — just search for a package with the promisify
function.
In real life, some tasks have no asynchronous code, but they still need promises to build a chain.
You can make that promise yourself:
const promise = new Promise((resolve) => resolve());
// promise.then ...
It's the same for a promise that ends unsuccessfully:
const promise = new Promise((resolve, reject) => reject());
// promise.catch ...
For these tasks, there are abbreviations that make the code look cleaner:
const promise1 = Promise.resolve();
// promise1.then
const promise2 = Promise.reject();
// promise2.catch ...
Device
Technically, a promise is an object that has three states:
- Pending
- Fulfilled
- Rejected
A promise starts in the pending state. Then, it uses functions resolve
and reject
, and translated into one of the final states — fulfilled or rejected. In these states, the promise cannot be rolled back or changed to another terminal state.
In other words, after calling resolve
there's no way to make the promise have the rejected state by calling the reject
function.
Recommended materials
Are there any more questions? Ask them in the Discussion section.
The Hexlet support team or other students will answer you.
For full access to the course you need a professional subscription.
A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.