javascript - 如何知道 XMLHttpRequest 是否已经完成?
问题描述
我正在使用表单字段上传多个文件
<input type="file" accept="image/jpeg, image/png" multiple
循环将所有文件发送到上传功能
// Upload photo function
var upload = function (photo, callback) {
var formData = new FormData();
formData.append('photo', photo);
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState === 4) {
callback(request.response);
}
}
request.open('POST', 'upload.php');
request.responseType = 'json';
request.send(formData);
};
for (var i = 0; i < files.length; i++) {
upload(resizedFile, function (response) { });
}
如果所有文件都成功上传,想要重定向..
//all files finished, go to ...
if(response !== null && typeof response !== 'object') var response = JSON.parse(response);
window.location.href = "my-new-url.php?id="+response.id;
我的问题,重定向是在所有上传完成之前完成的。如何让脚本等待所有 xmlhttprequests 完成?
编辑
我像这样改变了上传功能,用jQuery上传。从 for 循环中多次调用该函数,那么我如何等待所有循环/jquery 调用完成,然后重定向?
function upload (photo, callback) {
var fd = new FormData();
fd.append('photo',photo);
return $.ajax({
url: 'upload.php',
type: 'post',
data: fd,
contentType: false,
processData: false,
success: function(response){
},
});
};
解决方案
首先,我会承诺上传功能。使用 JQuery 会更短,因为它$.ajax
返回一个 thenable 对象,但是使用老式的 vanilla JS,它看起来像这样:
var upload = function (photo) {
return new Promise(function(resolve, reject) {
var request = new XMLHttpRequest();
request.onload = function() {
if (request.status >= 200 && request.status < 300) {
resolve(request.response);
} else {
reject(request.statusText);
}
};
request.onerror = function() { reject(request.statusText) }
request.open('POST', 'upload.php');
request.responseType = 'json';
var formData = new FormData();
formData.append('photo', photo);
request.send(formData);
})
}
另见:http ://ccoenraets.github.io/es6-tutorial-data/promisify/
然后我会在一个数组中收集这些承诺:
var uploads = files.map(function(file) { return upload(resizeFile(file)); })
(或者像你一样简单地迭代并将它们推送到一个数组中)
然后您可以使用此代码来处理所有上传的完成:
Promise.all(uploads)
.then(function(results) { /* do the redirect */ })
.catch(function(error) { console.log(error); });
另请参阅:https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
注意:为什么其他答案中建议的计数错误?因为它不处理任何请求失败时的条件。您将无法检测到这种情况,并且您永远不会达到满足的条件。Promise(和 async/await)是处理异步操作的正确方法,比如 ajax 请求。
[更新]
这是使用最新 JS 语言功能的 JQuery 方法:
var upload = (photo) => {
photo = resizeFile(photo);
let formData = new FormData();
formData.append('photo', photo);
return $.ajax({
type: 'POST',
url: 'upload.php',
data: formData
}) // check other the options of ajax method, you might need them
}
let uploads = files.map(upload);
$.when.apply($,uploads)
.done(_ => { /* do the redirect */ })
.fail(e => { /* handle error */ })
后半部分可以用async/await
语法来写:
async somefunction(){
// rest of the code
try {
await $.when.apply($,uploads)
/* do the redirect */
} catch(ex) {
/* handle error */
}
}
注意,它$.ajax
返回Deferred,它是一个 JQuery 对象,与 Promise 兼容。
推荐阅读
- java - 算术问答游戏中每次运行时游戏屏幕上的随机问题数
- android - Nativescript 模拟器安装头疼
- highcharts - 如何为 Highcharts 标记添加单独的注释样式工具提示?
- javascript - 如何使一个组件具有全屏背景图像?
- android-studio - 为什么android studio 3.3版没有Toolbar(Action Bar)
- c++ - 析构函数是移动 ctor/assignment 的 RHS 上唯一调用过的东西吗?
- html - 样式化 ul 标签和 li 标签不影响其他 ul 和 li
- php - 多个表单和多个提交,一个提交按钮
- microsoft-graph-api - 如何对 AAD 租户中所有服务主体的导出进行分区?
- r - 循环遍历 2 个数据框以识别常见列