Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 31.03.2017, 08:58
Интересующийся
Отправить личное сообщение для Prowler Посмотреть профиль Найти все сообщения от Prowler
 
Регистрация: 09.07.2008
Сообщений: 28

действия после окончания img.onload
Доброго времени суток!
Задача получить из массива с файлами изображений объекты base64.
Есть простенький кусок кода стянутый с стековера:
function getBase64(file) {
   var reader = new FileReader();
   reader.readAsDataURL(file);
   reader.onload = function () {
     console.log(reader.result);
     return reader.result; //добавляем возврат из функции
   };
   reader.onerror = function (error) {
     console.log('Error: ', error);
   };
}

и пробуем прогнать массив через эту функцию, например так:
//массив с картинками доступен в переменной test
function getArray(){
var newArray=[];
for(var i=0; i<test.length; i++){
newArray.push(getBase64(test[i]));
}
return newArray;
}

Конечно возвращается пустой массив, т.к. функции не дожидаются завершения события onload и выполняются возвращая в массив undefined. Можно ли сохраняя текущий подход как-то дождаться завершения чтения файла и только тогда продолжить выполнения функций? Ну или другим методом добиться искомого результата?
Ответить с цитированием
  #2 (permalink)  
Старый 31.03.2017, 17:00
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

Prowler,

function getBase64(test, callback) {
    var newArray = [];
    for (var i = 0; i < test.length; i++) {
        var reader = new FileReader;
        reader.onload = function() {
            newArray.push(reader.result);
            if (test.length == newArray.length) callback(newArray)
        };
        reader.onerror = function(error) {
            console.log("Error: ", error)
        };
        reader.readAsDataURL(test[i])
    }
};

Последний раз редактировалось рони, 31.03.2017 в 17:39.
Ответить с цитированием
  #3 (permalink)  
Старый 31.03.2017, 17:09
Аватар для Alexandroppolus
Профессор
Отправить личное сообщение для Alexandroppolus Посмотреть профиль Найти все сообщения от Alexandroppolus
 
Регистрация: 25.10.2016
Сообщений: 1,012

примерно так. Написано на коленке, не проверял, дебажить тебе )

function getArray(test) {
	return Promise.all(test.map(function(file) {
		return new Promise(function(resolve) {
 			var reader = new FileReader();
 			reader.onload = function () {
	 			resolve(reader.result);
 			};
 			reader.onerror = function (error) {
	 			resolve(null);
 			};
			reader.readAsDataURL(file);
		});
	}));
}

// использование
getArray(test).then(function(arr) {
	// в массиве arr будут все base64
});
Ответить с цитированием
  #4 (permalink)  
Старый 06.04.2017, 21:07
Интересующийся
Отправить личное сообщение для Prowler Посмотреть профиль Найти все сообщения от Prowler
 
Регистрация: 09.07.2008
Сообщений: 28

рони,
Благодарю.
Alexandroppolus,
Попробовал разобраться таки с незнакомой темой промисов. Кажется вот разобрался, но возник вопрос. Не отходя от вашего примера: как узнать, что все изображения уже загрузились?
Попробую объяснить. Функцию которая конвертируют изображения вызывает внешний код. В ответ он хочет получить уже готовый массив в base64. Если здесь
getArray(test).then(function(arr) {
});

arr присвоить другой переменной, например, из замыкания или глобальной, мы получим наш массив как хотелось. Но пока они туда будут грузиться, внешний код может уже их использовать.
Вижу только выход из ситуации с переходом на цепочку промисов. Других вариантов нет?

Решил дописать, думаю, понятней будет. Это делается как часть большой формы. Кроме загрузки изображений есть другие данные. Чтобы упростить задачу, все они должны собраться в JSON. Пользователь может попытаться отправить данные пока идет загрузка картинок(маловероятно, но все же). Собрать остальные данные - легко. Но как проверить что массив уже содержит все base64 ну и... вернуть его?

Последний раз редактировалось Prowler, 06.04.2017 в 21:21.
Ответить с цитированием
  #5 (permalink)  
Старый 07.04.2017, 09:54
Аватар для Alexandroppolus
Профессор
Отправить личное сообщение для Alexandroppolus Посмотреть профиль Найти все сообщения от Alexandroppolus
 
Регистрация: 25.10.2016
Сообщений: 1,012

Prowler,
вызов функция, переданной в then - это и есть тот момент, когда все картинки загрузились. Это обеспечивается методом Promise.all - он получает массив промисов, ждет когда они все зарезолвятся (или хотя бы один зареджектится, но это не наш случай), и резолвится массивом результатов.

Разумеется, все дальнейшие действия ты можешь делать только внутри функции then, ну или использовать этот промис для построения других конструкций из промисов.

Например, если надо что-то грузить после этих картинок, делай так
getArray(test).then(function(arr) {
   return otherGetDataPrimise(arr);
}).then(function(data) {
  // здесь data - то что было загружено
});


если параллельно с картинками, то вот так
Promise.all([
  getArray(test),
  otherGetDataPrimise()
]).then(function(data) {
  // data - массив. data[0] - массив картинок, data[1] - данные, полученные otherGetDataPrimise
});


В общем, можно произвольно комбинировать. Ты можешь прямо на листочке нарисовать схему, что и в каком порядке должно грузиться, оформить подгрузку каждой части как отдельную функцию, возвращающую промис, и потом легко и непринужденно собрать из них схему любой сложности. Эта схема опять же будет возвращать промис, который зарезолвится полным набором результатов, и в его then ты выполнишь финальные действия с полученными данными.

Обработку ошибок можно навтыкать по ситуации. getArray из моего предыдущего поста (и функции внутри него) не реджектится, из предположения, что если хотя бы часть картинок загрузилось - "и то хлеб". А если надобно по схеме "все или ничего", то просто реджектишь в reader.onerror, и весь getArray вылетает в ошибку.
Ответить с цитированием
  #6 (permalink)  
Старый 07.04.2017, 10:52
Интересующийся
Отправить личное сообщение для Prowler Посмотреть профиль Найти все сообщения от Prowler
 
Регистрация: 09.07.2008
Сообщений: 28

Alexandroppolus,
Ну да, я это и имел ввиду говоря о цепочках. Т.к. с темой только познакомился, подумал (ну мало ли!), что может быть есть какой то механизм в них который каким-либо образом синхронизирует выполнение в функции.... ну что-то вроде невозможного:
function myFunc(){
//собираем данные с первой формы
//собираем данные со второй формы 
Promise.all().then(); //сгребаем картинки
//продолжаем сбор данных со второй формы
//а теперь с третьей формы
}


Ну да, чудес не бывает. Нагородим цепочку. Благодарю
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Ссылка обрабатывается/отображается после обновления страницы Kimtom Общие вопросы Javascript 3 14.04.2014 15:03
Переход на url после окончания цикла vas88811 Events/DOM/Window 16 21.12.2013 12:44
Остановка выполнения скрипта до определенного действия пользователя. Matisumi Общие вопросы Javascript 3 28.01.2013 00:21
Повернуть изображение после его загрузки (jquery) art_maestro jQuery 0 13.09.2012 21:50
ищу DatePicker с временем, списком выбора месяца и возможностью смены месяца после вы Kri0-Gen jQuery 3 10.07.2012 16:07