如何使用when then 在一个函数中按顺序发送文件上传,这也是一个延迟的承诺?
-
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!')});
不幸的是,在重定向到成功页面之前我无法上传大量文件。
我已经尝试了各种 StackOverflow 解决方案来了解如何执行此操作。到目前为止没有任何效果。请指教。
为了节省空间,一些代码已被截断。
解决方案
你所有的承诺都是并行的,而不是连续的。
一个承诺代表一个 已经运行 任务。与 C# 任务或其他抽象不同,JavaScript 中的 Promise 已经启动。表示尚未开始的任务的方法是返回一个 Promise 的函数。
自从 promises[i]
已经是一个承诺——当你这样做的时候 promise.then(object)
它不会添加 .then 处理程序,而是立即返回。 .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;
您现在也不需要使用when,因为您返回了 单身的 承诺。我假设您不需要这里的实际结果(而只是为了知道成功/失败)。
您只需执行以下操作:
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;
}
不隶属于 StackOverflow