5

Tôi có một yêu cầu đòi hỏi chuỗi lời hứa. Trong ứng dụng Ionic của tôi, tôi cần phải lặp qua danh sách các tệp và nén chúng. Sau đó, zip cần phải được lưu trữ trên thiết bị chính nó (iPhone trong trường hợp này).Chaining nhiều lời hứa, bao gồm cả Promise.all

Tôi đã có danh sách các tệp cần được nén trong một mảng. Vì vậy, tôi đang lặp qua chúng và sử dụng $ cordovaFile để lấy nội dung của các tệp này. Sau đó, tôi thêm nhị phân vào một đối tượng JSZip. Kết quả cuối cùng phải là nội dung nhị phân của tất cả các tệp cần được thêm vào tệp zip.file để tệp nén có thể được tạo.

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

Khi zip.file có tất cả nội dung, tôi đang gọi một hàm khác trong JSZip sẽ tạo mã zip. Điều này cũng sẽ trả về một lời hứa, vì vậy tôi cần phải chuỗi đến $ cordovaFile.writeFile, để zip có thể được viết cục bộ. $ cordovaFile.writeFile cũng trả về một Promise hứa hẹn cuối cùng trong chuỗi.

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

Đây là cách mã hoàn chỉnh trông giống như

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

Challenge là sau khi Promise.all hoàn tất, không có gì được thực thi. Vì vậy, không có gì bắt đầu 'sau đó (function (zipData)' được thực hiện.

tôi cảm thấy nó có cái gì để làm với cách tôi đang chaining Promises. Bất kỳ trợ giúp sẽ được đánh giá cao.

Trả lời

1

Điều này là do forEach trả về undefined, do đó Promise.all sẽ được giải quyết ngay lập tức. Bạn nên thay đổi điều đó thành .map.

Hơn nữa, hãy nhớ rằng đối số zipData của bạn sẽ không phải là những gì bạn mong đợi. Đối số của lời hứa này sẽ chứa mọi kết quả được trả lại từ zip.file(file, binaryData, {binary: true}).

Trong trường hợp này, bạn không cần số zipData. Biến số zip sẽ thực hiện công việc. Trong đoạn code dưới đây tôi cũng đã đơn giản hóa chuỗi lời hứa bằng cách loại bỏ một lời hứa dư thừa trong vòng lặp và lấy một số .then bên ngoài.

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

Cảm ơn bạn Georgi-it, không chỉ trả lời câu hỏi mà còn giúp sửa các lỗi khác trong cách tiếp cận mà tôi thậm chí không biết. – kayasa

+0

Vui vì tôi có thể giúp @kayasa –

0

Lý do Promise.all không bao giờ giải quyết là filesList.forEach không bao giờ trả bất kỳ giá trị

tôi nghĩ rằng thay đổi để fileList.map sẽ giải quyết vấn đề của bạn

vì vậy, thay đổi mã của bạn như sau:..

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)); 
     }) 
} 
Các vấn đề liên quan