Like callbacks, promises allow asynchronous operations to run in parallel. And you can do it automatically, so you don't have to manually track the end of the operations.
All you need to do is collect an array of promises and pass them to the Promise.all
function. It will return the usual promise, which you can use to keep building a chain. The data from the first then
will be an array containing the data of all operations performed.
import fsp from 'fs/promises';
const unionFiles = (inputPath1, inputPath2, outputPath) => {
const promise1 = fsp.readFile(inputPath1, 'utf-8');
const promise2 = fsp.readFile(inputPath2, 'utf-8');
// The input is an array of promises
const promise = Promise.all([promise1, promise2]);
// Don't forget to return
return promise.then(([data1, data2]) => fsp.writeFile(outputPath, `${data1}${data2}`));
};
The result is effective code that's also easy to understand. And there are no extra variables here. Although Promise.all
returns the data in the same order as the promises passed to it, it doesn't guarantee the order of operations. Don't ever count on it, all operations run simultaneously, and which operation will run earlier or later is unknown.
The Promise.all
function doesn't care how the promise collection was obtained. All it needs is an array of those promises as input. So we can easily combine Promise.all
with any function that returns collections.
The example below is an array of paths to the files that need to be read and their contents displayed. The first thing in the code is to create an array of promises, then pass it to Promise.all
and finally show the contents of the files on the screen:
// An array of promises
const promises = filepaths.map((filepath) => fsp.readFile(filepath, 'utf-8'));
const promise = Promise.all(promises);
// Display the contents of each file
promise.then((contents) => contents.map(console.log));
The function map
goes through each file and sends it to our function which calls fsp.readFile()
. Each call returns a promise. If you try to print this array, it'll look like this:
const promises = filepaths.map((filepath) => fsp.readFile(filepath, 'utf-8'));
console.log(promises);
[
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
...
]
The Promise.all
always runs operations simultaneously, and these operations don't depend on each other in any way. So, no error other than the program aborting will stop requests.
Errors in at least one of the promises won't prevent all the other requests from being executed. However, if at least one promise fails, the entire result of Promise.all
will be marked as inaccurate and control will pass to the next catch
.
To avoid this, we can pass not only promises to Promise.all
, but also promises with error handlers attached to them, which will return the data with a success mark.
const promises = filepaths.map((filepath) => fsp.readFile(filepath, 'utf-8')
.then((v) => ({ result: 'success', value: v }))
.catch((e) => ({ result: 'error', error: e })));
const promise = Promise.all(promises);
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.