Goal
I have a bunch of file names in an array, and would like to read the contents of the first of the files that exists. They're config files, so it's important that the order is deterministic, so I can't use .race()
. The version I have below maps over each file in order, tries to load it, and if it loads successfully, calls resolve.
Problems
Here are a couple of issues with this implementation:
- Calling
resolve(...)
doesn't actually exit the loop, so the program opens every file in the list, even when doesn't need to. - The rejection condition (at
this is required to reject when we don't receive any files
) seems like a hack. However, if it's not here, the promise is never rejected. - The resolution code seems suspiciously like a promise anti-pattern.
Are there any better ways to do structure this? I could probably do it with a single Promise.filter
call, but I don't want to query every file if I don't need to.
Thanks
Code
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));
var _ = require('lodash');
new Promise((resolve, reject) => {
// Resolve with the first of the files below that exists
return Promise.mapSeries(
['./file_that_doesntexist.json', '../file_that_might_exist.json', './file_that_doesnt_exist_either.json', '../file_that_exists.json']
, (filename) => fs.readFileAsync(filename, 'utf-8')
.then(file => {
resolve([filename, file]);
return true;
})
.catch(_.stubFalse)
)
.then(files => { // this is required to reject when we don't receive any files
if(!files.some(x => x))
reject('did not receive any files');
});
})
.then(function([filename, configFile]) {
// do something with filename and configFile
})
.catch(function(err) {
console.error(err)
})