Three asynchronous file uploads in JavaScript

  • 2021-01-25 06:55:38
  • OfStack

Asynchronous file uploading is a skill that every front end must master for better user experience. Here I suggest three ways to do asynchronous file uploads.

Upload with third party controls, such as Flash,ActiveX and other browser plug-ins.

Simulate asynchronous uploads using hidden iframe.

Use XMLHttpRequest2 to implement asynchronous uploads.

The first use of browser plug-in upload, the need for a set of low-level coding skills, here I will not speak, so as not to mislead children, put forward this point we can baidu.

The second uses hidden iframe to simulate asynchronous uploads. Why are we talking about simulation here? Because we are actually putting the result in a hidden iframe, we are not making the current page jump, which feels like an asynchronous operation.

Post the code first:


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-">
<title> hidden iframe Upload a file </title>
<script type="text/javascript" src="jquery The path ..."></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"> Attachment:  <input type="file" name="myfile" style="display: inline"></p>
<p id="upbtn"><input style="padding-left:px;padding-right: px;" type="submit" value=" Asynchronous upload ">
<span id="uptxt" style="display: none"> Are uploading ...</span></p>
</form>
<div id="flist" style="border:px dotted darkgray;"></div>
<script>
//  A callback after the upload is complete 
function uploadFinished(fileName) {
addToFlist(fileName);
loading(false);
}

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

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

There are two key aspects to this technique:

1.form specifies target, and the submitted results are directed back to the hidden ifram. (that is, the target of form and the name of iframe).

2. After the submission is completed, the page in iframe communicates with the main page to inform the uploading result and server file information

How to communicate with the main page?

We used nodejs to return 1 window.parent after receiving the file. A method defined on the main page that tells you the file upload is complete when executed. The code is simple:


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(""));
}, );
});

After execution, open the Developer option and you will find that some data is returned from the server in the hidden iframe.

The third uses XMLHttpRequest2 for true asynchronous uploads.

Let's post the code first:


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-">
<title>xhr level  Asynchronous upload </title>
<script type="text/javascript" src="jquery The path ..."></script>
</head>
<body>
<div>
<p id="upfile"> Attachment:  <input type="file" id="myfile" style="display: inline"></p>
<p id="upbtn">
<input style="padding-left:px;padding-right: px;" type="button" value=" Asynchronous upload " onclick="upload();">
<span id="uptxt" style="display: none"> Are uploading ...</span>
<span id="upprog"></span>
<button id="stopbtn" style="display:none;"> Stop uploading </button>
</p>
</div>
<div id="flist" style="border:px dotted darkgray;"></div>
<script>
function upload() {
// . To prepare FormData
var fd = new FormData();
fd.append("myfile", $("#myfile")[].files[]);

//  create xhr object 
var xhr = new XMLHttpRequest();
//  Monitor status, real-time response 
// xhr  and  xhr.upload  There are progress The event, xhr.progress Is the download schedule, xhr.upload.progress Is the upload schedule. 
xhr.upload.onprogress = function(event) {
if (event.lengthComputable) {
var percent = Math.round(event.loaded * / event.total);
console.log('%d%', percent);
$("#upprog").text(percent);
}
};
//  Transmission start event 
xhr.onloadstart = function(event) {
console.log('load start');
$("#upprog").text(' To upload ');

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

loading(true);
};
// ajax The procedure successfully completed the event 
xhr.onload = function(event) {
console.log('load success');
$("#upprog").text(' Uploaded successfully ');

console.log(xhr.responseText);
var ret = JSON.parse(xhr.responseText);
addToFlist(ret.fname);
};
// ajax An error event occurred during the procedure 
xhr.onerror = function(event) {
console.log('error');
$("#upprog").text(' An error occurred ');
};
// ajax Be cancelled 
xhr.onabort = function(event) {
console.log('abort');
$("#upprog").text(' The operation was cancelled ');
};
// loadend When the transmission ends, it will be triggered whether it succeeds or fails 
xhr.onloadend = function (event) {
console.log('load end');
loading(false);
};
//  initiate ajax Request transfer data 
xhr.open('POST', '/upload', true);
xhr.send(fd);
}
function addToFlist(fname) {
var temp = ["<p id='" + fname + "'>",
fname,
"<button onclick='delFile(\"" + fname + "\");'> delete </button>",
"</p>"
];
$("#flist").append(temp.join(""));
}
function delFile(fname) {
console.log('to delete file: ' + fname);
// TODO:  Please implement 
}
function loading(showloading) {
if (showloading) {
$("#uptxt").show();
$("#stopbtn").show();
} else {
$("#uptxt").hide();
$("#stopbtn").hide();
}
}
</script>
</body>
</html>

It's a bit of code, but it's easy to understand. As anyone who has used AJAX knows, the XHR object provides one onreadystatechange callback method to listen to the entire request/response process. Several more progress events have been added to the XMLHttpRequest2 level specification. There are six events:

1.loadstart: Triggered when the first byte of response data is received.

2.progress: Continuously fires during the receiving response.

3.error: Triggered on request error.

4.abort: Triggered when the connection is terminated due to a call to the abort() method.

5.load: Triggered when complete response data is received.

6.loadend: Emitted after communication is completed or error,abort,load events are triggered.

This time we can read the code: when the transfer event starts, we add a click event to the stop transfer button, and the abort method is built in to stop the transfer. If not, it will upload normally until the transfer is completed. The backend code is similar to the second method.

Each of these methods has its pros and cons, so let's make a brief summary.

The third side control is interactive and controllable, because close to the bottom layer, its performance is also very good. However, because it is difficult to write and usually requires you to install the plug-in yourself, sometimes you may need to write it yourself.

The hidden iframe method I personally think is a very thoughtful method, iframe can help us to do a lot of things. This approach has broad browser compatibility and does not require the installation of plug-ins. But it is not interactive, the upload process is uncontrollable, and the performance is very good.

XHR2 level pure ajax upload, it must be a higher version of the browser 1 point (ie9+). However, it is extremely interactive, you can see the progress of the upload and it is controllable.

Development can take different approaches as required. I personally feel that these file uploads, especially the second one that provides an idea, take full advantage of some of the ES97en tag features, may be something that we developers need to think about more.


Related articles: