Control of the issuance of asynchronous results
-
I'm writing a program that shows the image preference by adding it to the tables. There's a field in the neighboring cells for the name, the gate and the source of downloaded photos that I'm also filling, after which I download all this information along with the server files. I use the object.
FileReader
which, in turn, records files by methodreadAsDataUrl
♪ But the problem is, this method works asynchronously and as a result, I can see the previews not in the order in which the files will be loaded on the server, but the preview itself does not match the files behind them, it's a mix-up. This has created a problem because the descriptions of the file that the user (name, tag, source) does not correspond to the picture.That's what it looks like. Loading process:
Load result:
https://stackoverflow.com/questions/19778843/order-issue-with-append-in-a-file-reader People have already raised and solved a similar problem, but I don't know how to use these ideas in my case, when the elements of the table are dynamically created for each bonus. Please help.
My code is:
JavaScript
$(document).ready(function () {
$("#fileUpload").on('change', function () { //Get count of selected files var countFiles = $(this)[0].files.length; var imgPath = $(this)[0].value; var extn = imgPath.substring(imgPath.lastIndexOf('.') + 1).toLowerCase(); var image_holder = $("#image-holder"); image_holder.empty(); if (extn == "gif" || extn == "png" || extn == "jpg" || extn == "jpeg") { if (typeof(FileReader) != "undefined") { //loop for each file selected for uploaded. var newElem = document.createElement('table'); newElem.id = 'tl'; newElem.align = 'center'; newElem.border = 0; for (var i = 0; i < countFiles; i++) { var reader = new FileReader(); reader.onload = function (e) { var newRow = newElem.insertRow(0); var newCell1 = newRow.insertCell(0); newCell1.innerHTML = "<input type='text' class='form-control' " + "placeholder='Source' name='source' style='margin: 15px'>"; var newCell2 = newRow.insertCell(0); newCell2.innerHTML = "<input type='text' class='form-control' " + "placeholder='Tags' name='tags' style='margin: 10px'>"; var newCell3 = newRow.insertCell(0); newCell3.innerHTML = "<input type='text' class='form-control' " + "placeholder='Name' name='name' style='margin-left: 5px'>"; var newCell4 = newRow.insertCell(0); $("<img />", { "src": e.target.result, "class": "thumb-image" }).appendTo(newCell4); }; document.getElementById("image-holder").appendChild(newElem); reader.readAsDataURL($(this)[0].files[i]); image_holder.show(); } } else { alert("This browser does not support FileReader."); } } else { alert("Please select images only"); } });
});
HTML:
<form method="POST" action="upload" enctype="multipart/form-data">
<input id="fileUpload" name="file" multiple="multiple" type="file"/>
<br/>
<input type="submit" value="Upload" class="btn btn-primary btn-lg">
<br/>
<div id="image-holder"/>
</form>
-
For consecutive loading, use may be made https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise
To this end, FileReader can be loaded into a function that will return the Promise that will be allowed when the picture is downloaded.
She can look like:
function loadImage(image){ return new Promise(function(resolve, reject){ var fileReader = new FileReader(); fileReader.onload = function(e){ resolve(e.target.result); } fileReader.readAsDataURL(image); }); }
Used https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then You can sign for an event that happens when Prmoise is ready.
For example:
loadImage().then(function(imageAsDataUrl){ ... });
Thus, a chain of asynchronous operations can be assembled that will be followed by each other.
The final view may be:
var queue = Promise.resolve();
[].reduce.call(this.files,function(queue, file, index){
return queue.then(function(){
return loadImage(file).then(function(imageAsDataUrl){
var newRow = newElem.insertRow(0);
var newCell1 = newRow.insertCell(0);
newCell1.innerHTML = "<input type='text' class='form-control' " +
"placeholder='Source' name='source' style='margin: 15px'>";
var newCell2 = newRow.insertCell(0);
newCell2.innerHTML = "<input type='text' class='form-control' " +
"placeholder='Tags' name='tags' style='margin: 10px'>";
var newCell3 = newRow.insertCell(0);
newCell3.innerHTML = "<input type='text' class='form-control' " +
"placeholder='Name' name='name' style='margin-left: 5px'>";
var newCell4 = newRow.insertCell(0);$("<img />", { "src": imageAsDataUrl, "class": "thumb-image" }).appendTo(newCell4); }); });
}, Promise.resolve()).then(function(){
// все картинки загрузились
image_holder.show();
})
slight derogation:
$(this)[0]
It's the same as it is.this
You can check with the following expression$(this)[0] === this
Come back.true
♪