2017-01-06 3 views
1

私はすべての画像ファイルを含むzipファイルを作成するためにJSzipを使用しています。私はXMLHttpRequestを使ってループ内の外部リンクから画像を取得しました。私のコードzipfileによると、XMLHttpRequestを完了する前に作成します。したがって、空のzipファイルを返します。すべてのファイルをループした後にzipファイルを作成するには?すべてのファイルをループした後にzipファイルを作成する方法は?

$(document).on('click', '.download', function(){ 
    var path = $(this).attr("data-id"); 
    var count = $(this).attr("value"); 
    var storageRef = firebase.storage().ref(); 
    var zip = new JSZip(); 
    console.log(count); 

    for (i = 1; i <= count; i++) { 
     console.log(path+i+".png"); 
     var imagePath = path+i+".png"; 

     // Create a reference to the file we want to download 
     var starsRef = storageRef.child(imagePath); 

     starsRef.getDownloadURL().then(function(url) { 
     // Insert url into an <img> tag to "download" 
     ImageUrl = url; 

     var xhr = new XMLHttpRequest(); 
     xhr.open('GET', ImageUrl, true); 
     xhr.responseType = "arraybuffer"; 
     xhr.onreadystatechange = function(evt) { 
      if (xhr.readyState === 4) { 
       if (xhr.status === 200) { 

        zip.file(i+".png", xhr.response); 

       } 
      } 
     }; 
     xhr.send(); 
     }) 
    } 
    zip.generateAsync({type:"blob"}) 
    .then(function(content) { 
     // see FileSaver.js 
     saveAs(content, "my.zip"); 
    }); 
}); 
+1

をループがある前に、あなたが 'zip.generateAsync'を呼んでいるように思えます'zip.file(i +"。png "、xhr.response);を初めて呼び出す前に実行できるようになりました。ループを 'promise'にラップすると、必要に応じて' zip.generateAsync'をチェーンすることができます。これは、[ループで多くの約束を返して、それらを待つ方法](http://stackoverflow.com/questions/31426740/how-to-return-many-promises-in-a-loop-and-wait -for-them-all-to-do-other-stuff) – Nope

+0

はい。それは私の質問で述べたように問題です。問題は、私は状況を克服する考えがないということです。私はこれがAJAXの要求に対してよりスリムであると思う。 – Bandara

+0

@Franのコメントに加えて、[async calls loop javascriptを待つ]のようなキーワードを使ってSOを検索すると(http://stackoverflow.com/search?q=wait+for+async+calls+loop+javascript)、どのようにこれを行うことができる多くの結果。 – michaPau

答えて

1

JSZipはコンテンツとして約束をサポートしています。つまり、各HTTP呼び出しを約束にラップし、明示的に待機しないことができます。

最初の関数downloadUrlAsPromiseは、xhr呼び出しをPromiseにラップします。第2の関数downloadFirebaseImageは、第1の関数の約束を約束してgetDownloadURLから約束します。結果はxhrコンテンツの約束です。

あなたが直接そのようなJSZipに約束与えることができることをしたら:

zip.file(i+".png", downloadFirebaseImage(imagePath)); 

詳しい方法:

function downloadUrlAsPromise (url) { 
    return new Promise(function (resolve, reject) { 
    var xhr = new XMLHttpRequest(); 
    xhr.open('GET', url, true); 
    xhr.responseType = "arraybuffer"; 
    xhr.onreadystatechange = function(evt) { 
     if (xhr.readyState === 4) { 
     if (xhr.status === 200) { 
      resolve(xhr.response); 
     } else { 
      reject(new Error("Ajax error for " + url + ": " + xhr.status)); 
     } 
     } 
    }); 
    xhr.send(); 
    }); 
} 

function downloadFirebaseImage(storageRef, path) { 
    var starsRef = storageRef.child(imagePath); 
    return starsRef.getDownloadURL().then(function(url) { 
    return downloadUrlAsPromise(url); 
    }); 
} 


// ... 
for (i = 1; i <= count; i++) { 
    console.log(path+i+".png"); 
    var imagePath = path+i+".png"; 
    zip.file(i+".png", downloadFirebaseImage(imagePath)); 
} 

zip.generateAsync({type:"blob"}) 
.then(function(content) { 
    // see FileSaver.js 
    saveAs(content, "my.zip"); 
}); 
+0

完全に動作します。ありがとう。 – Bandara

関連する問題