JavaScript中三种异步上传文件方式

作者:半夏

时间:2026-10-29

浏览:98

本文详解前端实现异步文件上传的三种主流方式:利用浏览器插件、通过隐藏iframe模拟以及基于XMLHttpRequest2的纯AJAX上传。文章对比了各方案在浏览器兼容性、交互体验、开发难度及性能表现上的优劣,并提供了Node.js后端处理示例,帮助开发者根据实际需求选择最佳方案。

文章目录

为了提升用户体验,前端开发中掌握异步文件上传技术至关重要。本文主要探讨实现这一功能的三种不同路径。

基于浏览器插件的上传方案

第一种方案是利用Flash、ActiveX等浏览器插件或第三方控件进行上传。

第二种方案是通过创建一个隐藏的iframe来模拟异步上传的效果。

第三种方案则是利用XMLHttpRequest2标准来实现真正的异步文件上传。

关于第一种利用浏览器插件的方式,由于涉及较深的底层编码且需要用户安装特定插件,本文不作深入展开,建议感兴趣者自行查阅相关资料。

基于隐藏iframe的模拟上传

第二种方案被称为“模拟”异步,因为本质上是将表单提交的目标指向一个隐藏的iframe,从而避免当前页面发生跳转,给用户造成异步操作的错觉。

具体实现代码如下:


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-">
<title>隐藏的iframe上传文件</title>
<script type="text/javascript" src="jquery路径..."></script>
</head>
<body>
<iframe name="frm" style="display:none"></iframe>
<form action="/upload" enctype="multipart/form-data" method="post" target="frm" onsubmit="loading(true);">
<p id="upfile">附件: <input type="file" name="myfile" style="display: inline"></p>
<p id="upbtn"><input style="padding-left:px;padding-right: px;" type="submit" value="异步上传">
<span id="uptxt" style="display: none">正在上传...</span></p>
</form>
<div id="flist" style="border:px dotted darkgray;"></div>
<script>
// 上传完成后的回调
function uploadFinished(fileName) {
addToFlist(fileName);
loading(false);
}

function addToFlist(fname) {
var temp = ["<p id='" + fname + "'>",
fname,
"<button onclick='delFile(\"" + fname + "\");'>删除</button>",
"</p>"
];
$("#flist").append(temp.join(""));
}

function loading(showloading) {
if (showloading) {
$("#uptxt").show();
} else {
$("#uptxt").hide();
}
}
</script>
</body>
</html>

该技术实现的核心要点包含两个方面:

首先,form表单需设置target属性,使其值与隐藏iframe的name属性一致,这样表单提交后的结果就会定向返回到该iframe中。

其次,在提交完成后,iframe内的页面需与主页面进行通信,告知上传结果及服务端返回的文件信息。

那么,iframe与主页面如何进行通信呢?

以Node.js后端为例,在接收文件后,后端会返回一段脚本,调用主页面定义的window.parent方法,从而触发上传完成的逻辑。相关代码如下:


router.post('/upload', multipartMiddleware, function(req, res) {
var fpath = req.files.myfile.path;
var fname = fpath.substr(fpath.lastIndexOf('\\') + );
setTimeout(function() {
var ret = ["<script>",
"window.parent.uploadFinished('" + fname + "');",
"</script>"];
res.send(ret.join(""));
}, );
});

执行上述代码后,打开浏览器开发者工具,可以在隐藏的iframe中看到服务器返回的具体数据。

基于XMLHttpRequest2的纯异步上传

第三种方案是利用XMLHttpRequest2标准进行真正的异步上传,这是目前较为推荐的方式。

相关实现代码如下:


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-">
<title>xhr level 异步上传</title>
<script type="text/javascript" src="jquery路径..."></script>
</head>
<body>
<div>
<p id="upfile">附件: <input type="file" id="myfile" style="display: inline"></p>
<p id="upbtn">
<input style="padding-left:px;padding-right: px;" type="button" value="异步上传" onclick="upload();">
<span id="uptxt" style="display: none">正在上传...</span>
<span id="upprog"></span>
<button id="stopbtn" style="display:none;">停止上传</button>
</p>
</div>
<div id="flist" style="border:px dotted darkgray;"></div>
<script>
function upload() {
// .准备FormData
var fd = new FormData();
fd.append("myfile", $("#myfile")[].files[]);

// 创建xhr对象
var xhr = new XMLHttpRequest();
// 监听状态,实时响应
// xhr 和 xhr.upload 都有progress事件,xhr.progress是下载进度,xhr.upload.progress是上传进度
xhr.upload.onprogress = function(event) {
if (event.lengthComputable) {
var percent = Math.round(event.loaded * / event.total);
console.log('%d%', percent);
$("#upprog").text(percent);
}
};
// 传输开始事件
xhr.onloadstart = function(event) {
console.log('load start');
$("#upprog").text('开始上传');

$("#stopbtn").one('click', function() {
xhr.abort();
$(this).hide();
});

loading(true);
};
// ajax过程成功完成事件
xhr.onload = function(event) {
console.log('load success');
$("#upprog").text('上传成功');

console.log(xhr.responseText);
var ret = JSON.parse(xhr.responseText);
addToFlist(ret.fname);
};
// ajax过程发生错误事件
xhr.onerror = function(event) {
console.log('error');
$("#upprog").text('发生错误');
};
// ajax被取消
xhr.onabort = function(event) {
console.log('abort');
$("#upprog").text('操作被取消');
};
// loadend传输结束,不管成功失败都会被触发
xhr.onloadend = function (event) {
console.log('load end');
loading(false);
};
// 发起ajax请求传送数据
xhr.open('POST', '/upload', true);
xhr.send(fd);
}
function addToFlist(fname) {
var temp = ["<p id='" + fname + "'>",
fname,
"<button onclick='delFile(\"" + fname + "\");'>删除</button>",
"</p>"
];
$("#flist").append(temp.join(""));
}
function delFile(fname) {
console.log('to delete file: ' + fname);
// TODO: 请实现
}
function loading(showloading) {
if (showloading) {
$("#uptxt").show();
$("#stopbtn").show();
} else {
$("#uptxt").hide();
$("#stopbtn").hide();
}
}
</script>
</body>
</html>

虽然代码量稍多,但逻辑清晰。熟悉AJAX的开发者知道,XHR对象提供了onreadystatechange回调来监听请求状态。在XMLHttpRequest2规范中,新增了多个进度事件,具体包括以下6种:

1. loadstart:在接收到响应数据的第一个字节时触发。

2. progress:在接收响应期间持续不断地触发,用于显示上传进度。

3. error:在请求发生错误时触发。

4. abort:当调用abort()方法终止连接时触发。

5. load:在接收到完整的响应数据时触发。

6. loadend:在通信完成,或者触发error、abort、load事件后触发。

在代码解读中可以看到,当传输开始后,我们在停止按钮上绑定了点击事件,内部调用abort方法即可中断上传。若用户不点击停止,则文件会正常上传直至完成。其后端处理逻辑与第二种方法类似。

三种方案对比总结

上述三种方法各有优劣,下面进行简要总结。

第三方控件方案交互性和可控性较好,且因接近底层,性能优异。但其缺点在于开发难度大,通常需要用户手动安装插件,甚至需要开发者自行编写插件代码。

隐藏iframe方案被认为是一种富有创意的实现方式,充分利用了iframe的特性。其优势在于广泛的浏览器兼容性且无需安装插件;但劣势在于交互性较差,上传过程不可控,且性能表现一般。

基于XMLHttpRequest2的纯AJAX上传方案要求浏览器版本较高(如IE9及以上)。其最大优势是交互性极佳,用户可以实时查看上传进度,并且可以随时控制上传过程。

开发者可根据具体项目需求选择合适的方案。个人建议,尤其是第二种方法,更多体现的是一种利用HTML标签特性的编程思想,值得开发人员深入思考。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章