How to read multiple files asynchronously with promises, then proceed
Asked Answered
H

1

7

I'm new to promises and using the rsvp implementation.

I want to asynchronously read a list of files, then proceed to another task only when all files have been read.

I've got as far as the basic structure to read one file, and chain to the next task:

var loadFile = function (path) {
    return new rsvp.Promise(function (resolve, reject) {
        fs.readFile (path, 'utf8', function (error, data) {
            if (error) {
                reject(error);
            }
            resolve(data);
        });
    });
};

loadFile('src/index.txt').then(function (data) {
    console.log(data);
    return nextTask(data);
}).then(function (output) {
    //do something with output
}).catch(function (error) {
    console.log(error);
});

I want to do something like this:

loadFile(['src/index.txt', 'src/extra.txt', 'src/another.txt']).then( ...

I've seen arrays of promises and hash of promises in the docs, but I don't know which is most relevant, or how to use them. I need an example of their use in the context of my problem above to understand them.

Haydenhaydn answered 22/2, 2015 at 19:36 Comment(0)
H
7

You want to use RSVP.all():

var promises = ['path1', 'path2', 'path3'].map(loadFile);

RSVP.all(promises).then(function(files) {
  // proceed - files is array of your files in the order specified above.
}).catch(function(reason) {
  console.log(reason); // something went wrong...
});

Feel free to make promises an object and use RSVP.hash() instead:

var promises = {
  file1: loadFile('path1'),
  file2: loadFile('path2'),
  file3: loadFile('path3')
};

RSVP.hash(promises).then(function(files) {
  // files is an object with files under corresponding keys:
  // ('file1', 'file2', 'file3')
}).catch(function(reason) {
  console.log(reason); // something went wrong...
});

(thanks to @Benjamin Gruenbaum for suggestion to use .map())

Hydrastine answered 22/2, 2015 at 19:39 Comment(6)
Before loading the files, I have an unrelated preceding task that returns a different promise. How would I chain RSVP.all() to wait for this dependent task?Haydenhaydn
Just call RSVP.all() in the resolve callback of your preceding task.Hydrastine
I couldn't get the object version to work: [Error: Array Methods must be provided an Array]. Never mind - that's what RSVP.hash is for.Haydenhaydn
@mtmacdonald: oops, thanks for pointing it out! I updated the answer to reflect that (+use .map() in the first code block), for the future generations.Hydrastine
is there any way to use map when the promise takes multiple arguments? E.g. the same problem, but with writeFile().Haydenhaydn
@matmacdonald: sadly, I don't think so. At least not in any clean/seamless way. Function given to .map() is always executed with three arguments: value of the element in the array, index of it, and finally - full array the .map() is executed on.Hydrastine

© 2022 - 2024 — McMap. All rights reserved.