Я пишу программу, которая показывает превью изображений, добавляя их в ячейки таблицы. В соседних ячейках есть поля для имени, тегов и источника загружаемых фотографий, которые я также заполняю, после чего загружаю всю эту информацию вместе с файлами на сервер. Я использую объект FileReader, который в свою очередь записывает файлы методом readAsDataUrl. Но проблема в том, что этот метод работает асинхронно и как результат я вижу превью не в том порядке, в котором файлы будут загружены на сервер, а сами превью не соответствуют файлам, которые за ними стоят, получается перемешка. Это породило проблему, поскольку описания файла, которые вносит пользователь (имя, тег, источник) в результате не соответствуют картинке.
Вот как это выглядит (обратите внимание на описания). Процесс загрузки:
Результат загрузки:
Здесь люди уже поднимали и решили похожую проблему, но я не знаю, как применить эти идеи в моем случае, когда для каждого превью динамически создаются элементы таблицы. Прошу помощи.
Мой код:
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 = "";
var newCell2 = newRow.insertCell(0);
newCell2.innerHTML = "";
var newCell3 = newRow.insertCell(0);
newCell3.innerHTML = "";
var newCell4 = newRow.insertCell(0);
$("", {
"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:
Ответ
Для организации последовательной загрузки можно использовать Promise
Для этого загрузку изображения с помощью FileReader, можно вынести в функцию, которая будет возвращать Promise, который разрешится тогда, когда картинка загрузится.
Она может выглядеть так:
function loadImage(image){
return new Promise(function(resolve, reject){
var fileReader = new FileReader();
fileReader.onload = function(e){ resolve(e.target.result); }
fileReader.readAsDataURL(image);
});
}
Используя функцию then можно подписаться на событие, которое произойдет, когда Prmoise перейдет в состояние готов.
например так:
loadImage().then(function(imageAsDataUrl){ ... });
Таким образом можно собрать цепочку асинхронных операций, которые будут выполняться друг за другом.
Итоговый вид может быть таким:
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 = "";
var newCell2 = newRow.insertCell(0);
newCell2.innerHTML = "";
var newCell3 = newRow.insertCell(0);
newCell3.innerHTML = "";
var newCell4 = newRow.insertCell(0);
$("", {
"src": imageAsDataUrl,
"class": "thumb-image"
}).appendTo(newCell4);
});
});
}, Promise.resolve()).then(function(){
// все картинки загрузились
image_holder.show();
})
небольшое отступление: $(this)[0] это то же самое, что и this, можете проверить с помощью следующего выражения $(this)[0] === this вернет true
Комментариев нет:
Отправить комментарий