Combining multiple promises, including Promise.all

I have a requirement that requires a chain of Promises. In my Ionic app, I need to iterate over the list of files and pin them. Then the zip must be saved on the device itself (iPhone in this case).

I already have a list of files that need to be fixed in an array. So, I repeat them and using $ cordovaFile, getting the binay contents from these files. Then I add the binary to the JSZip object. The end result should be that the binary content of all files should be added to the zip.file so that a zip file can be created.

//wrapping in Promise.all so that we don't proceed until we have the content of all files added to zip var zip = new JSZip(); return Promise.all( filesList.forEach(function(file) { console.log('file to be added using $cordovaFile '+file); // Getting the content of each file using $cordovaFile. This returns a promise. return $cordovaFile.readAsBinaryString(cordova.file.dataDirectory + $rootScope.username, file) .then(function(binaryData) { return new Promise(function(resolve, reject) { //Adding content of all files to zip.file so that it can be zipped in the next step. resolve(zip.file(file, binaryData, {binary: true})); }) }) .catch(function(error) { console.log('Error during fetch content or zipping '+JSON.stringify(error)); }) }) ) 

Once zip.file has all the contents, I call another function in JSZip that will generate the zip. This will also return the promise, so I need to bind to $ cordovaFile.writeFile so that the zip code can be written locally. $ cordovaFile.writeFile also returns the promise that will be the last in the chain.

 .then(function(zipData) { // async request to generate the zip return zipData.generateAsync({type:"blob"}); }).then(function (blob) { // once we have the zip, save it to the device $cordovaFile.writeFile(cordova.file.dataDirectory+$rootScope.username, 'abc.zip', blob, true) .then(function(data) { console.log('Zip file written to device at '+cordova.file.dataDirectory+$rootScope.username); }) }).catch(function(error) { console.log('Error while zipping and writing '+JSON.stringify(error)); }) 

Here is the full code

 var zipFiles = function(filesList) { var zip = new JSZip(); return Promise.all( filesList.forEach(function(file) { return $cordovaFile.readAsBinaryString(cordova.file.dataDirectory + $rootScope.username, file) .then(function(binaryData) { return new Promise(function(resolve, reject) { resolve(zip.file(file, binaryData, {binary: true})); }) }) .catch(function(error) { console.log('Error during fetch content or zipping '+JSON.stringify(error)); }) }) ) .then(function(zipData) { return zipData.generateAsync({type:"blob"}); }).then(function (blob) { $cordovaFile.writeFile(cordova.file.dataDirectory+$rootScope.username, 'abc.zip', blob, true) .then(function(data) { console.log('Zip file written to device at '+cordova.file.dataDirectory+$rootScope.username); }) }).catch(function(error) { console.log('Error while zipping and writing '+JSON.stringify(error)); }) } 

The challenge is that nothing is done after Promise.all completes. So, nothing starts (function (zipData) "is executed.

I feel this has something to do with how I cling to Promises. Any help would be greatly appreciated.

+5
source share
2 answers

This is because forEach returns undefined , so Promise.all resolved immediately. You must change this to .map .

Also, keep in mind that your zipData argument zipData not be what you expect. These promise arguments will contain every result returned from zip.file(file, binaryData, {binary: true}) .

In this case, you do not need zipData . The zip variable will do the job. In the code below, I also simplified the promises chain by removing the redundant promise in the loop and selecting one .then from the outside.

 var zipFiles = function (filesList) { var zip = new JSZip(); var zipFilesPromises = filesList.map(function (file) { return $cordovaFile.readAsBinaryString(cordova.file.dataDirectory + $rootScope.username, file) .then(function (binaryData) { return zip.file(file, binaryData, { binary: true }); }); }); return Promise.all(zipFilesPromises) .then(function () { return zip.generateAsync({ type: "blob" }); }) .then(function (blob) { return $cordovaFile.writeFile(cordova.file.dataDirectory + $rootScope.username, 'abc.zip', blob, true); }) .then(function (data) { console.log('Zip file written to device at ' + cordova.file.dataDirectory + $rootScope.username); }) .catch(function (error) { console.log('Error while zipping and writing ' + JSON.stringify(error)); }) } 
+1
source

The reason Promise.all never resolves is because filesList.forEach never returns any values.

I think modifying fileList.map will solve your problem.

So, change your code as follows:

 var zipFiles = function(filesList) { var zip = new JSZip(); return Promise.all( filesList.map(function(file) { return $cordovaFile.readAsBinaryString(cordova.file.dataDirectory + $rootScope.username, file) .then(function(binaryData) { return new Promise(function(resolve, reject) { resolve(zip.file(file, binaryData, {binary: true})); }) }) .catch(function(error) { console.log('Error during fetch content or zipping '+JSON.stringify(error)); }) }) ) .then(function(zipData) { return zipData.generateAsync({type:"blob"}); }).then(function (blob) { $cordovaFile.writeFile(cordova.file.dataDirectory+$rootScope.username, 'abc.zip', blob, true) .then(function(data) { console.log('Zip file written to device at '+cordova.file.dataDirectory+$rootScope.username); }) }).catch(function(error) { console.log('Error while zipping and writing '+JSON.stringify(error)); }) } 
0
source

All Articles