次に、遅延約束である関数でファイルアップロードを順番に送信するときに使用する方法?
-
26-12-2019 - |
質問
jQueryを使ってファイルの配列をアップロードするつもりです。
この意図は、uploadFilesUsingAjax()
と呼ばれる関数で折り返されます。
var uploadFilesPromise = uploadFilesUsingAjax();
$.when(uploadFilesPromise).done(function (uploadFilesAjaxResult) {
// redirect to success page...
.
何か他のものをする前に、すべてのファイルを正常にアップロードするのを待つ必要があります。
uploadFilesUsingAjax()
、
私はこのようにして私のコードを書きました
function uploadFilesUsingAjax() {
var files = pages; // pages is a global variable which is an array of files
var url = "/users/" + currentUser.id + "/files.json";
var type = "POST";
console.info('files length:' + files.length);
if (files.length > 0) {
var promises=[];
for (var i = 0; i < files.length; i++) {
var data = new FormData();
var postData = {};
var file = files.getByIndex(i);
var key = i + 1;
if (typeof (file.id) !== "undefined" && file.id > 0) {
data.append(key, JSON.stringify(file));
} else {
data.append(key, file);
}
var request = $.ajax({
//this is the php file that processes the data
url: url,
//POST method is used
type: type,
//pass the data
data: data,
//Do not cache the page
cache: false,
xhr: function() {
// custom xhr
myXhr = $.ajaxSettings.xhr();
if(myXhr.upload) { // check if upload property exists
myXhr.upload.addEventListener('progress',updatePagesProgress, false); // for handling the progress of the upload
}
return myXhr;
},
// DO NOT set the contentType and processData
// see http://stackoverflow.com/a/5976031/80353
contentType: false,
processData: false,
//success
success: function (json) {
// json is already an object thanks to cakephp code to serialize
//if POST is a success expect no errors
if (json.error == null && json.result != null) {
currentUser = json.result.User;
// error
} else {
alert(json.error);
}
}
});
promises.push( request);
}
var promise = promises[0];
for (var i = 1; i < promises.length; i++) {
promise = promise.then(promises[i]);
}
return promise.done(function () { console.log('all!')});
.
残念ながら、私は成功ページにリダイレクトされる前にたくさんのファイルをアップロードすることはできませんでした。
これを行う方法については、さまざまなスタックオーバーフローソリューションを試してみました。これまでのところ何も機能しません。アドバイスしてください。
スペースを節約するためにいくつかのコードが切り捨てられました。
解決
すべての約束は並行してシーケンシャルではありません。
Promiseは、既に既に稼働しているタスクを表します。 C#タスクや他の抽象化とは異なり、JavaScriptでの約束はすでに開始されています。開始されていないタスクを表す方法は、約束を返す機能です。
promises[i]
はすでに約束です - promise.then(object)
を実行すると、それは。 .then
関数ではない引数を無視します。
これが早く戻ってきた理由は、最初の約束が果たすとすぐに返します。 .when
も必要ありません。そのようなアップロードプロセスを作成する関数を作成します。
function createUploadTask(file,i){
return function(){
var data = new FormData();
var postData = {};
var file = files.getByIndex(i);
var key = i + 1;
if (typeof (file.id) !== "undefined" && file.id > 0) {
data.append(key, JSON.stringify(file));
} else {
data.append(key, file);
}
return $.ajax({...}); // return the promise
}
}
.
今、あなたはタスクにファイルをマッピングすることができます:
var tasks = files.map(createUploadTask);
.
注意事項は、ファイルのアップロードを介した約束を返す各関数です。彼らは約束されていません。
今、あなたはそれらをチェーンすることができます:
var p = tasks[0](); // start off the chain
for(var i = 1; i < tasks.length; i++){
// chain the next task, note, that we're passing a _function_ here
// when you return a promise from a `.then` it will fulfill when that promise
// fulfills, in our case the $.ajax
p = p.then(tasks[i]);
}
return p;
.
あなたは今 single 約束を返すので、あなたは今使用する必要はありません。私はあなたがここでの実際の結果を必要としないと思います(しかし、成功/失敗を知るためだけに)。
単にする:
function uploadFilesUsingAjax() {
// settings
if(tasks.length === 0){
// a method MUST always either return either synchronously or asynchronously never
// both, always return a promise. Otherwise you get API hell.
var d = $.Deferred();
d.reject(new Error("Called uploadFiles with no files to upload"));
return d.promise;
}
tasks = pages.map(createUploadTask)
var p = tasks[0](); // call first one
for(var i = 1; i < tasks.length; i++) p = p.then(tasks[i]);
return p;
}
.