JavaScript中三种异步上传文件方式
本文详解前端实现异步文件上传的三种主流方式:利用浏览器插件、通过隐藏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标签特性的编程思想,值得开发人员深入思考。
JavaScript闭包与类(Class)的区别及适用场景对比
2026-11-05 15:48:57
JavaScript入门要学ES6吗?let与箭头函数等新特性解析
2026-11-05 14:49:16
JavaScript 8种数据类型详解:基本类型与引用类型的区别
2026-11-05 14:25:15
怎么在JavaScript中使用async/await优化Ajax异步流程
2026-11-05 13:56:15
JavaScript replace回调函数实现动态正则替换逻辑
2026-11-05 13:52:13
