If there are promises in the project, then all the code only work through them. Unfortunately, not all libraries have an interface for working with promises and work the old-fashioned way, using callbacks. In such cases, functions need to be wrapped, or “promisified”. Promises are created using 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 expects a function to be called when they're created. It's within this function that we need to perform the asynchronous operation (on the callback) that we want to turn into a promise. Promise throws two callbacks into this function:
resolve
— must be called if the asynchronous operation is completed successfully. It takes the result of this operation as input.reject
— must be called in case of an error. The input, respectively, is an error.These functions take exactly one argument, which is then passed either to then
(as data) or catch
(as error)). And it's enough for at least one of these functions is called. It may well be necessary to create a promise, which always ends successfully. This is easy to do without ever calling reject
.
At the end, the new new Promise()
construct returns a real promise, which we can work with in the way we're used to:
promise
.then(console.log)
.catch(console.log)
What if you need to wrap two asynchronous operations, or three, or even more? You have to wrap each of them independently. In other words, one asynchronous operation - one constructor new Promise
. By the way, this task can be automated, and there's a special function is built into node.js that makes promises from asynchronous functions:
import util from 'util';
import fs from 'fs';
const stat = util.promisify(fs.stat);
stat('.').then((stats) => {
// Do something with `stats`
}).catch((error) => {
// Handle the error.
});
This can also be done in fronted, just google the package that has the promisify
function.
In real life, there are tasks that have no asynchronous code, but that still need a promise to build a chain. You can make this 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 special abbreviations added that make the code look cleaner:
const promise1 = Promise.resolve();
// promise1.then
const promise2 = Promise.reject();
// promise2.catch ...
Technically, a promise is an object that has three states (see finite-state automata and automata programming): pending, fulfilled and rejected. A promise starts in the pending, state, and then, using functions ("events", as they say in automata theory) resolve
and reject
are translated into one of the final (terminal) states fulfilled or rejected. Once in these states, the promise can no longer roll back or go to another terminal state. I.e., after calling resolve
, there's no way to make the promise have the rejected, state by calling the reject
function.
The Hexlet support team or other students will answer you.
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.
Programming courses for beginners and experienced developers. Start training for free
Our graduates work in companies:
From a novice to a developer. Get a job or your money back!
Sign up or sign in
Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.