2017-05-01 17 views
0

我有一個Web應用程序,它從URL中收集各種文件並將它們放在一起放入zip壓縮文件中。將JS promisies包裝到函數中

我正在使用JSZip來處理zip文件。下面是包括位於同一服務器上的其他檔案文件的內容的代碼示例:

<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

它工作得很好。 JSZipUtils.getBinaryContent返回來自URL的zip文件的二進制內容的承諾。 zip.loadAsync()讀取二進制內容並將其包含到存檔中。 zip.generateAsync在RAM中構建一個zip存檔的表示形式,因此我們可以稍後下載它。

但是,我需要將zip.loadAsync()換成可以多次調用的函數。我已經試過這樣的事情:

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

但它看起來像zip.loadAsync()的需求,以等待完成。如果我只是運行上面的函數,然後生成一個zip文件,它會忽略我試圖包含的zip文件的內容。

我對於promisies的工作方式不太好,所以我需要一個函數的幫助,它會接收一個url並等待promise的解析,所以我可以多次調用它,並定期zip.file,然後觸發一個郵編一代。謝謝。

+0

你能澄清你的目標是什麼?你是否想用'loadAsync'讀取多個zip文件並將它們合併到一個zip文件中? – nderscore

+0

這聽起來像是你試圖讓一個函數「等待」,直到一個承諾在它返回之前解決。你不能用Javascript做到這一點。沒有辦法採取異步操作,並以某種方式將其包含在返回異步結果的同步函數中。這是不能做到的。這是經常要求的,它不能完成。相反,你必須學習如何編寫正確的異步代碼,並在函數中返回一個promise,然後在該promise上使用'.then()'來知道什麼時候完成了異步操作,然後纔在那個'.then )'處理程序是否會啓動序列中的下一步? – jfriend00

+0

@nderscore是的,這就是我想要做的。我們可能會認爲我們不知道應該合併多少檔案/用戶可能會添加額外的檔案。 – mkrl

回答

1

您可以將JSZipUtils.getBinaryContent方法包裝在Promise中並生成它們的數組。然後,您可以使用Promise.all()創建一個新的承諾,該承諾將解決數組中的所有承諾何時解決的問題。

這裏是我會怎麼做一個例子:

// 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

謝謝,我明白了。但是你提供的代碼不起作用,我會試着弄清楚這裏有什麼問題。 – mkrl

+1

@mkrl我能夠修復代碼並使其工作。我已經更新了我的答案,並且在jsfiddle上有一個演示:https://jsfiddle.net/ghvw7brt/ – nderscore