Javascript, сплайсированный FileReader для больших файлов с промисами, как?

Я пытаюсь использовать FileReader для последовательного чтения нескольких файлов, используя для этого обещания. Проблема в том, что мне нужно разделить операции чтения на несколько частей, чтобы сделать их выполнимыми. Поступая так, я теряю цепочку Promise. Это то, что происходит в следующем коде, где я получаю журнал консоли here, затем catched (что означает, что я потерял цепочку), затем inside и затем finished. Почему-то обещание при загрузке не соблюдается.

Вот код (пожалуйста, перейдите к последнему РЕДАКТИРОВАТЬ, тем не менее я сохраняю исходный текст)

var reader = new FileReader();
reader.onloadend = function(e) {
  if (e.target.readyState == 2) {
    console.log('inside')
    start = temp_end;
    temp_end = start + BYTES_PER_CHUNK;
    if (temp_end > end) temp_end = end;
    upload();
  }
};

Array.reduce(function(promise, item) {
  start = 0;
  temp_end = start + BYTES_PER_CHUNK;
  end = parseInt(totalsize);
  if (temp_end > end) temp_end = end;
  uploading_file = item;
  return upload()
  .then(function(){
    console.log('not shown');
  })
  .catch(console.log('catched'));
},0);

function upload() {
  return new Promise(function(resolve,reject) {
    if (start < end) {
      console.log('here')
      var chunk = uploading_file.slice(start, temp_end);
      reader.readAsBinaryString(chunk);
    } else {
      console.log('finished')
      uploading_file = null;
      resolve();
    }
  }
}

РЕДАКТИРОВАТЬ1: новый код, который я пробую, по-прежнему console.log stop 1 появляется перед upload и here 2

        var start = 0;
        var temp_end = start + BYTES_PER_CHUNK;
        var end = parseInt(item.size);
        if (temp_end > end) temp_end = end;
        uploading_file = item;
        console.log('here 1')
        Promise.resolve().then(function() {
            return upload();
        })
        .then(function(){
            console.log('here 2')
        })
        .catch(console.log('stop 1'));

        function upload() {
            console.log('upload')
            if (start < end) {
                var chunk = uploading_file.slice(start, temp_end);
                var reader = new FileReader();
                reader.readAsArrayBuffer(chunk);
                reader.onload = function(e) {
                    if (e.target.readyState == 2) {
                        start = temp_end;
                        temp_end = start + BYTES_PER_CHUNK;
                        if (temp_end > end) temp_end = end;
                        return upload();
                    }
                }
            } else {
                console.log('finished')
                uploading_file = null;
                return Promise.resolve();
            }
         }

РЕДАКТИРОВАТЬ 2: Журналы перехвата были там из-за отсутствия функции(). Следующий код, кажется, работает, но я не вижу интересующего меня значения content в конце.

Проблема в том, что обещания здесь действительно не работают, говорится в console.log.

here 1
here 2
here 4
here 3

Код:

        var item; // item is a file
        var BYTES_PER_CHUNK = 100000;
        var start = 0;
        var temp_end = start + BYTES_PER_CHUNK;
        var end = parseInt(item.size);
        if (temp_end > end) temp_end = end;
        var content = ''; // to be filled by the content of the file
        var uploading_file = item;
console.log('here 1');
        Promise.resolve().then(function() {
console.log('here 2');
            return upload();
        })
        .then(function(content){
console.log('here 4');
            console.log(content); // this is empty (!!)
        })
        .catch(function(){
            console.log('stop 1')
        });

        function upload() {
            if (start < end) {
                var chunk = uploading_file.slice(start, temp_end);
                var reader = new FileReader();
                reader.readAsArrayBuffer(chunk);
                reader.onload = function(e) {
                    if (e.target.readyState == 2) {
                        content += new TextDecoder("utf-8").decode(e.target.result);
                        start = temp_end;
                        temp_end = start + BYTES_PER_CHUNK;
                        if (temp_end > end) temp_end = end;
                        return upload();
                    }
                }
            } else {
                uploading_file = null;
                console.log(content); // it shows the content of the file
console.log('here 3');
                return Promise.resolve(content);
            }
        }

person GWorking    schedule 07.08.2016    source источник
comment
Мне очень трудно понять, что вы пытаетесь сделать. У вас много необъявленных переменных, общее состояние и неверный код (Array.reduce? Является ли Array переменной в вашем реальном коде?). И upload, похоже, не имеет ничего общего с загрузкой, а возвращенное обещание иногда не разрешается или не отклоняется. Я попытаюсь угадать попытку, но если бы вы могли уточнить, какова цель кода.   -  person Jacob    schedule 07.08.2016
comment
Пожалуйста, перейдите к последнему РЕДАКТИРОВАТЬ окончательный код. В любом случае Array.reduce должен был означать, что у меня есть массив и что я использовал сокращение, но эта часть кода действительно не важна для проблемы, которую я хочу изолировать. Надеюсь, с последним кодом понятнее, чего я хочу добиться? Конечная цель — читать файлы порциями и сохранять контроль над этим с помощью промисов.   -  person GWorking    schedule 07.08.2016
comment
Теперь намного понятнее, спасибо.   -  person Jacob    schedule 07.08.2016
comment
@GWorking сработал, похоже, этому парню нужно то же решение, что и вашему stackoverflow .com/questions/57206375/multifile-upload-as-chunks   -  person Jayavel    schedule 26.07.2019
comment
@Jayavel Я сбросил ссылку на этот вопрос, я не работал с загрузкой файлов с ... 2 года назад, здесь немного заржавело :)   -  person GWorking    schedule 03.08.2019


Ответы (1)


Ваша функция upload() не всегда возвращает обещание. Это происходит в условии else, но не в условии if. У вас есть оператор return, но он находится внутри обратного вызова, поэтому вызывающий upload не получит его.

Попробуйте изменить это на это:

function upload() {
  if (start < end) {
    return new Promise(function (resolve, reject) {
      var chunk = uploading_file.slice(start, temp_end);
      var reader = new FileReader();
      reader.readAsArrayBuffer(chunk);
      reader.onload = function(e) {
        if (e.target.readyState == 2) {
          content += new TextDecoder("utf-8").decode(e.target.result);
          start = temp_end;
          temp_end = start + BYTES_PER_CHUNK;
          if (temp_end > end) temp_end = end;
          resolve(upload());
        }
      }
    });
  } else {
    uploading_file = null;
    console.log(content); // it shows the content of the file
    return Promise.resolve(content);
  }
}

Теперь upload всегда возвращает Promise вместо undefined.

person Jacob    schedule 07.08.2016
comment
Фантастический. Это оно. Тысяча благодарностей! Теперь меня беспокоит использование Array.reduce здесь. Поскольку это было хорошо решено, я открываю для этого новый вопрос, stackoverflow.com/questions/38822187/, если у вас есть время - person GWorking; 08.08.2016