5

我有一个需要链接承诺的要求。在我的 Ionic 应用程序中,我需要遍历文件列表并压缩它们。然后 zip 需要存储在设备本身(在本例中为 iPhone)。

我已经有了需要压缩到数组中的文件列表。因此,我正在遍历它们并使用 $cordovaFile 获取这些文件的二进制内容。然后我将二进制文件添加到 JSZip 对象中。最终结果应该是将所有文件的二进制内容添加到 zip.file 中,以便可以生成一个 zip 文件。

//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));
                      })
                 })
             )

一旦 zip.file 包含所有内容,我将调用 JSZip 中的另一个函数来生成 zip。这也将返回一个承诺,因此我需要链接到 $cordovaFile.writeFile,以便可以在本地写入 zip。$cordovaFile.writeFile 还返回一个 Promise,它是链中的最后一个 Promise。

.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));
            })  

这是完整代码的样子

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));
            }) 
} 

挑战是在 Promise.all 完成后,没有任何东西被执行。因此,不会执行任何以“then(function(zipData)”开头的内容。

我觉得这与我链接 Promises 的方式有关。任何帮助将不胜感激。

4

2 回答 2

1

这是因为forEach返回undefined,因此Promise.all立即解决。您应该将其更改为.map.

此外,请记住,您的zipData论点不会是您所期望的。这个 Promise 的参数将包含从zip.file(file, binaryData, {binary: true}).

在这种情况下,您不需要zipData. 该zip变量将完成这项工作。在下面的代码中,我还通过删除循环中的冗余 Promise 并将其取出来简化了 Promise 链.then

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));
        })
} 
于 2016-09-10T15:07:14.760 回答
0

Promise.all 永远不会解决的原因是它filesList.forEach永远不会返回任何值。

我认为修改为fileList.map将解决您的问题。

所以改变你的代码如下:

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));
        }) 
} 
于 2016-09-10T14:58:11.503 回答