Уловить момент завершения асинхронной функции обратного вызова

#javascript #html #asynchronous

#javascript #HTML #асинхронный

Вопрос:

У меня есть этот код для рендеринга выбранного файла для загрузки:

   //1
  <input type="file" multiple id="my_html_uploader" />


//2
var files = myHtmlUploaderElem.files;
if (files.length > 0) {
  for (var i = 0, file1; file1 = files[i]; i  ) {
    var reader = new FileReader();
    reader.onload = (function(file2, i2) {
      return function(e) {
        alert("done!");
      };
    })(file1, i);

    reader.readAsDataURL(f);
  }
}
  

Как я могу уловить момент, когда обратный вызов reader.onload (…) был завершен для

а) отдельный файл

б) все файлы, которые были выбраны

?

Комментарии:

1. Для части B создайте глобальную переменную с длиной вашего массива. Каждый раз, когда выполняется ваш обратный вызов onload, вычтите единицу из счетчика и проверьте, равно ли оно нулю. если это так, выполните свой последний обратный вызов. Это то, что обещают. Все выполняется.

Ответ №1:

Создайте обещания, которые затем можно использовать Promise.all для ожидания их всех:

 const promises = []; // keep as much constant as possible

for (const file of files) { // way more beautiful, no need for an IIFE with "const" or "let"
  let reader = new FileReader();

  promises.push(new Promise((resolve, reject) => { // short for: function(resolve, reject) {
    reader.onload = event => resolve(event.target.result);
    reader.onerror = reject;
  }));

  reader.readAsDataURL(file);
}

Promise.all(promises).then(results => {
  alert("all loaded");
  // results is an array of file contents
}).catch(error => {
  // one of the files failed to load, handle that here
});
  

Комментарии:

1. будет ли это работать во всех браузерах, включая старые?

2. Нет, этого не произойдет. Перенесите его обратно в ES5, чтобы получить лучшую поддержку.

3. Как это сделать в ES5?