Загрузка файла по чанкам?

Изначально, загрузку сделал вот так:
export function сonvertFilesToByteArray(e) {
  const MAX_FILE_SIZE = 1024 * 1024 * 50; // 50MB
  const files = Object.keys(e.target.files);
  const asyncReadFile = eachFile =>
    new Promise((resolve, reject) => {
      if (e.target.files[eachFile].size > MAX_FILE_SIZE) {
        return reject([{ message: `Файл ${e.target.files[eachFile].name} слишком большой` }]);
      }
      const reader = new FileReader();
      const targetFileInfo = {
        contentType: e.target.files[eachFile].type,
        filename: e.target.files[eachFile].name,
      };
      reader.readAsArrayBuffer(e.target.files[eachFile]);
      reader.onload = () => {
        resolve({ ...targetFileInfo, body: Array.from(new Uint8Array(reader.result)) });
      };
      reader.onerror = error => reject(error);
    });

  return Promise.all(files.map(asyncReadFile));
}


Тут в константе files определяю, сколько у меня файлов и к каждому из них применяю функцию.

Но при таком подходе, не смотря на то, что использую Promise.all, при загрузке файла/файлов которые имеют размерность больше ~2МБ, то страница фризится, нельзя никак взаимодействовать с ней (скроллить есть возможность). Кроме как реализации, когда каждый файл бьётся по чанкам ничего в голову не пришло, чтобы исправить ситуацию.
Для этого переписал код на такой
export function сonvertFilesToByteArray(e) {
  const MAX_FILE_SIZE = 1024 * 1024 * 50; // 50MB
  const files = Object.keys(e.target.files);
  const asyncReadFile = eachFile =>
    new Promise((resolve, reject) => {
      if (e.target.files[eachFile].size > MAX_FILE_SIZE) {
        return reject([{ message: `Файл ${e.target.files[eachFile].name} слишком большой` }]);
      }
      const file = e.target.files[eachFile];
      let offset = 0;
      console.log(offset, 'offset', file.size, 'size');
      const defaultChunkSize = 64 * 1024; // bytes
      const fileReader = new FileReader();
      const blob = file.slice(offset, offset + defaultChunkSize);
      const isEndOfFile = () => offset >= file.size;
      const testEndOfFile = () => {
        if (isEndOfFile()) {
          console.log('Done reading file');
        }
      };
      fileReader.readAsArrayBuffer(blob);
      fileReader.onloadend = (event) => {
        const target = (event.target);
        if (target.error == null) {
          const result = target.result;
          offset += result.length;
          testEndOfFile();
          console.log(result, 'result');
          resolve(result);
        } else {
          reject(target.error);
        }
      };
    });

  return Promise.all(files.map(asyncReadFile));
}


Но тут я уперся в то, что не понимаю, как прочитать файл по чанкам (если он больше одного) и собрать его воедино, чтобы на выходе получить массив байтов и как в первом примере скомпоновать объект вида
{contentType: 'plain/text', filename: 'blabla', body: и вот тут мой буффер вида [123, 456, 23, ...] }

Который при завершении чтении всех файлов перебросится наружу, где написал следующий код
handleFileUpload = (e) => {
    сonvertFilesToByteArray(e)
      .then((result) => {
        runInAction(() => {
          this.files = [
            ...this.files,
            ...result,
          ];
        });
      })
      .catch(err => runInAction(() => {
        this.errors = [...this.errors, err[0].message];
      }));
  }


Комрады, выручайте :)
  • Вопрос задан
  • 703 просмотра
Пригласить эксперта
Ответы на вопрос 2
Stalker_RED
@Stalker_RED
А если не разбивать на чанки, а вместо этого вынести upload в webworker?
Ответ написан
bingo347
@bingo347
Бородатый программер
Для своей либы ws-api писал вот такую загрузку чанками:
https://github.com/bingo347/ws-api/blob/master/lib...
вот тут использование: https://github.com/bingo347/ws-api/blob/master/lib...
но собирается оно у меня уже на сервере node.js в ReadableStream:
https://github.com/bingo347/ws-api/blob/master/lib...
https://github.com/bingo347/ws-api/blob/master/lib...

покопайтесь в коде, думаю найдете себе решение, т.к. задача очень похожа
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через TM ID
Похожие вопросы
Энергомера Ставрополь
от 28 000 до 30 000 руб.
Digital Sharks Казань
от 60 000 до 65 000 руб.
RailCommerce Новосибирск
от 40 000 руб.
22 нояб. 2018, в 12:58
500 руб./за проект
22 нояб. 2018, в 12:16
1 руб./за проект