5

У меня есть требование, требующее цепочки обещаний. В моем приложении Ionic мне нужно перебрать список файлов и закрепить их. Затем zip необходимо сохранить на самом устройстве (iPhone в этом случае).Цепочка нескольких обещаний, включая Promise.all

У меня уже есть список файлов, которые необходимо закрепить в массиве. Итак, я повторяю их и используя $ cordovaFile, получая содержимое binay из этих файлов. Затем я добавляю двоичный код к объекту 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, которая будет генерировать молнию. Это также вернет обещание, поэтому мне нужно привязать к $ cordovaFile.writeFile, чтобы почтовый индекс можно было записать локально. $ cordovaFile.writeFile также возвращает обещание, которое было бы последним обещанием в цепочке.

.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, ничего не запускается на выполнение. Так, ничего, начиная «то (функция (zipData)» запускается на выполнение.

Я чувствую, что что-то делать с тем, как я СЦЕПЛЕНИЕ Promises. Любая помощь будет высоко оценен.

ответ

1

Это потому, что forEach возвращает undefined, таким образом Promise.all решает немедленно. Вы должны изменить это на .map.

Кроме того, имейте в виду, что ваш аргумент zipData не будет тем, что вы ожидаете. Аргументы этого обещания будут содержать каждый результат, возвращаемый с zip.file(file, binaryData, {binary: true}).

В этом случае вам не нужен zipData. Переменная zip выполнит задание. В приведенном ниже коде я также упростил цепочку обещаний, удалив избыточное обещание в цикле и получив один .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)); 
     }) 
} 
+0

Благодарю вас, Георгий, за то, что он не только ответил на вопрос, но и помог исправить другие ошибки в моем подходе, о которых я даже не подозревал. – kayasa

+0

Рад, что я помогу @kayasa –

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)); 
     }) 
} 
Смежные вопросы