2017-05-01 1 views
0

Ich habe eine Webanwendung, die verschiedene Dateien von URLs sammelt und sie in das Zip-Archiv zusammenfügt.Wrapping JS Promisies in eine Funktion

Ich verwende JSZip, um mit ZIP-Dateien zu arbeiten. Hier ist ein Codebeispiel, das Inhalt eines anderen ZIP-Archiv befindet sich auf dem gleichen Server umfasst:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> 
    <script type="text/javascript" src="./js/jszip.js"></script> 
    <script type="text/javascript" src="./js/jszip-utils.js"></script> 
    <script type="text/javascript" src="./js/FileSaver.js"></script> 

Downloading archive with contents from another archive 



<script> 

jQuery(function($) { 

      var zip = new JSZip(); 
      zip.file('see.txt','Regular files are being included with a single function call'); 



      function flash(){ 
      JSZipUtils.getBinaryContent('/version.zip', function(err, data) { 
       try { 
        zip.loadAsync(data) 
        .then(function(zip) { 
         zip.generateAsync({type: 'blob'}, 
         function(metadata) { 
         }) 
         .then(function(blob) { 
          saveAs(blob, 'result.zip'); 

         }, function(e) { 
          showError(e); 
         }); 
        }) 
        .then(function success() { 

        }); 
       } catch(e) {console.log(e)} 
       }); 
      }; 


     flash(); 



     return false; 

}); 

</script> 

Working JSFiddle with libs and examples included

Es funktioniert gut. JSZipUtils.getBinaryContent gibt ein Versprechen mit binärem Inhalt einer ZIP-Datei von der URL zurück. zip.loadAsync() liest Binärinhalte und fügt sie in das Archiv ein. zip.generateAsync erstellt eine Darstellung von ZIP-Archiv im RAM, so dass wir es später herunterladen können.

Allerdings muss ich zip.loadAsync() in eine Funktion wickeln, die ich mehrmals aufrufen kann. Ich habe so etwas wie dies versucht:

function zipmerge(source){ 
JSZipUtils.getBinaryContent(source, function (err, data) { 
    if(err) { 
     throw err; // or handle the error 
    } 
    var zip = new JSZip(); 
    zip.loadAsync(data); 
}); 
}; 

Aber es sieht aus wie zip.loadAsync() eine Wartezeit benötigt, um abgeschlossen zu werden. Wenn ich nur die obige Funktion ausführe und dann eine ZIP-Datei erzeuge, ignoriert sie einfach den Inhalt der ZIP-Datei, die ich eingeben möchte.

Ich bin nicht sehr gut mit, wie Promisies arbeiten, so brauche ich eine Hilfe mit einer Funktion, die eine URL erhalten und warten auf das Versprechen zu lösen, so dass ich es mehrere Male zusammen mit regulären zip.file aufrufen und dann auslösen konnte Zip-Generierung. Vielen Dank.

+0

Können Sie klären, was Ihr Ziel ist? Versuchen Sie, mehrere ZIP-Dateien mit 'loadAsync' zu lesen und sie in einer einzigen Zip-Datei zusammenzuführen? – nderscore

+0

Es klingt wie Sie versuchen, eine Funktion "warten", bis ein Versprechen verrechnet wird, bevor es zurückkehrt. Das kann man in Javascript nicht machen. Es gibt keine Möglichkeit, eine asynchrone Operation durchzuführen und sie irgendwie mit einer synchronen Funktion zu umbrechen, die das asynchrone Ergebnis zurückgibt. Das kann nicht gemacht werden. Es ist oft gefragt und es kann nicht getan werden. Stattdessen müssen Sie lernen, wie man richtigen asynchronen Code schreibt, wo Sie eine Zusage von Ihrer Funktion zurückgeben und '.then()' auf dieser Zusage verwenden, um zu wissen, wann die asynchrone Operation ausgeführt wurde und dann und nur dann innerhalb dieser '.) 'Handler starten Sie den nächsten Schritt in Ihrer Sequenz. – jfriend00

+0

@nderscore Ja, das ist was ich versuche zu tun. Wir können davon ausgehen, dass wir nicht wissen, wie viele Archive zusammengelegt werden sollen/der Benutzer kann zusätzliche Archive hinzufügen. – mkrl

Antwort

1

Sie können die JSZipUtils.getBinaryContent-Methode in eine Promise einbinden und daraus ein Array erstellen. Dann können Sie Promise.all() verwenden, um ein neues Versprechen zu erstellen, das löst, wenn alle Versprechen in einem Array aufgelöst wurden.

Hier ist ein Beispiel, wie ich es tun würde:

// function to read in a list of source zip files and return a merged archive 
function mergeZips(sources) { 
    var zip = new JSZip(); 

    return readSources(sources, zip) 
     .then(function() { 
      return zip; 
     }); 
} 

// generate an array of promises for each zip we're reading in and combine them 
// into a single promise with Promise.all() 
function readSources(files, zip) { 
    return Promise.all(
     files.map(function(file){ 
      return readSource(file, zip); 
     }) 
    ); 
} 

// promise-ified wrapper function to read & load a zip 
function readSource(file, zip) { 
    return new Promise(function(resolve, reject) { 
     JSZipUtils.getBinaryContent(file, function (err, data) { 
      if (err) { 
       reject(err); 
      } 
      // resolving the promise with another promise will pass the promise 
      // down the chain: 
      resolve(zip.loadAsync(data)); 
     }); 
    }); 
} 

// example usage: 
mergeZips([ 
    'file1.zip', 
    'file2.zip', 
    'file3.zip' 
]).then(function(zip) { 
    zip.generateAsync({type: 'blob'}) 
     .then(function(blob){ 
      saveAs(blob, 'result.zip') 
     }) 
}); 
+0

Danke, ich habe die Idee. Aber der von Ihnen angegebene Code funktioniert nicht, ich werde versuchen, hier etwas falsch zu machen. – mkrl

+1

@mkrl Ich konnte den Code reparieren und funktionierte. Ich habe meine Antwort aktualisiert und hier ist eine Demo auf jsfiddle: https://jsfiddle.net/ghvw7brt/ – nderscore