You're most of the way there, you just have to keep track of how many callbacks you've gotten and wait to resolve until you've gotten them all. Also, use reject(err)
rather than throw err
if there's a problem:
function getH2OfFiles(files) {
return new Promise((resolve, reject) => {
let h3s = [];
let complete = 0;
for (let i = 0; i < files.length; i++) {
fs.readFile(path.join(__src, 'documentation', files[i]), 'utf8', (err, data) => {
if (err) reject(err); // ***
const match = data.match(/<h3>(.*)<\/h3>/);
if (match) { // ***
h3s.push(match[1]);
}
if (++complete === files.length) { // ***
resolve(h3s); // ***
} // ***
})
}
});
}
(Note that I've also saved the result of the first call to match
rather than making the regex run twice.)
But, beware that you can receive those completions out of order, so h3s
may be out of order with the files (if it matters).
Or simplify through divide-and-conquer and give yourself a Promise-ified version of readFile
and then build the results once all files are read, via Promise.all
:
function readFilePromise(path, encoding) {
return new Promise((resolve, reject) => {
fs.readFile(path, encoding, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
function getH2OfFiles(files) {
return Promise.all(files.map(file => readFilePromise(path.join(__src, 'documentation', file), 'utf8')))
.then(results => {
const h3s = [];
results.forEach(result => {
const match = data.match(/<h3>(.*)<\/h3>/);
if (match) {
h3s.push(match[1]);
}
});
return h3s;
});
}
This also has the advantage that Promise.all
ensures you receive the array in the same order as the original array of promises (if it matters).
(Note: There are libs that will Promise-ify NodeJS APIs for you.)