Блокировка загрузки файлов с большими файлами

вступление

Чего я пытаюсь добиться, так это простой загрузки файла с индикатором прогресса с помощью redux-saga и реакции). У меня проблемы с получением этого указания, потому что загрузка файла блокируется, чего не должно быть.

Ожидаемое поведение

перед началом загрузки файла запускается повторный рендеринг, отображается счетчик, и окно не блокируется.

Текущее поведение

На данный момент у меня есть компонент с таблицей, которая показывает файл в строке. Оптимистичная строка добавляется со счетчиком в качестве контента, когда пользователи загружают файл. Как только файл будет загружен, оптимистичная строка будет заменена реальной строкой с именем файла и т. д. Когда я загружаю файл размером около 50 МБ, окно блокируется, и незадолго до загрузки файла (около 0,5 с) появляется спиннер а потом файл уже залит и опять пропадает спиннер.


примечания

  • Если заменить загрузку файла на new Promise(res => setTimeout(res, 5000)), все работает нормально => похоже, проблема с xhr/fetch.
  • Я реализовал то же самое, используя XHR, обещания и обратный вызов onProgress, чтобы убедиться, что проблема не в извлечении. реализация выглядит очень близко к: Также с этой реализацией я столкнулся с той же проблемой - блокировка почти до конца загрузки.
  • Если я помещаю операторы журнала в функцию рендеринга компонента, чтобы увидеть, выполняется ли повторный рендеринг перед загрузкой файла, я вижу (как только блок останавливается и файл загружается), что операторы журнала в функции рендеринга на самом деле правильно запускается с отметкой времени до того, как загрузка файла была выполнена.
  • В этой реализации я использую один и тот же редуктор: оптимистическое событие, а также реальное событие, возвращающее оптимистическое событие, проходят через один и тот же редуктор (названный здесь fileReducer).
  • использование второго редуктора и конкатенации вместо оптимистичной логики возврата помогает отображать счетчик раньше, но не помогает с блокировкой. Поэтому кажется, что промежуточное ПО также блокируется блокирующим вызовом.

сага: (postData использует выборку)

function* createDocument(partnerId, { payload, meta }) {
  const siteId = getSiteIdFromRoute();
  const {
    mediaGroupId,
    customArticleId,
    logicalComponentId,
    type,
    name,
    documentSrc,
    meta: metaFromFrontEnd
  } = payload;

  const commonEventId = uuid();
  const hans = {
    optimistic: true
  };
  const payloadBasic = {
    id: commonEventId,
    version: 0,
    aggregate: {
      id: uuid(),
      name: 'document'
    },
    context: {
      name: 'contentManagement'
    },
    payload: {
      name,
      type,
      links: {
        partnerId,
        siteId,
        logicalComponentId,
        customArticleId,
        mediaGroupId
      }
    }
  };

  // creates the optimistic (fake) row with a spinner in the file list component - action marked as optimistic which will be reverted.
  yield put(actions.denormalizeEvent({
    ...payloadBasic,
    name: 'documentCreated',
    optimistic: true,
    payload: {
      ...payloadBasic.payload,
      uploading: true
    }
  }));
  yield fork(executeDocumentUpload, type, siteId, partnerId, documentSrc, payloadBasic);
}

function* executeDocumentUpload(type, siteId, partnerId, documentSrc, payloadBasic) {
  const req = yield call(uploadDocument, type, siteId, partnerId, documentSrc);
  const body = yield req.json();
  const { meta: metaFromFileUpload, id } = body.response;
  // removes the optimistic (fake) row from the file list component and and adds the real row with more file information (optimistic event gets reverted in middleware)
  yield put(actions.sendCommandSuccess({
    ...payloadBasic,
    name: 'createDocument',
    payload: {
      ...payloadBasic.payload,
      meta: metaFromFileUpload
    }
  }));
}

function uploadDocument(type, siteId, partnerId, documentSrc) {
  let url;
  if (type === 'site' || type === 'mediaGroup' || type ===     'logicalComponent') {
    url = `/file/site/${siteId}/document`;
  } else if (type === 'customArticle') {
    url = `/file/partner/${partnerId}/document`;
  }
  return postData(url, documentSrc);
}

person Robin F.    schedule 06.03.2017    source источник
comment
Ожидаемое поведение происходит с файлом меньшего размера?   -  person SH-    schedule 06.03.2017
comment
@SH да, но, конечно, это менее заметно, потому что файл загружается намного быстрее.   -  person Robin F.    schedule 06.03.2017
comment
Что такое action.denormalizeEvent и action.sendCommandSuccess?   -  person SH-    schedule 06.03.2017
comment
@SH это среда CQRS - действие sendCommandSuccess отправит команду в домен - событие, возвращающееся из домена, приведет к действию denormalizeEvent. Таким образом, действие denormalizeEvent — это действие, запускаемое для изменения состояния редукции — его полезная нагрузка определяет, какой редюсер обрабатывает действие (есть оболочка). - Я добавлю комментарии к вопросам - спасибо.   -  person Robin F.    schedule 06.03.2017
comment
Трудно сказать точно, но кажется, что actions.denormalizeEvent зависит от более позднего события? (actions.sendCommandSuccess?)   -  person SH-    schedule 06.03.2017
comment
@SH- я добавил комментарии к коду - первый denormalizeEvent является оптимистичным, который запускает первый повторный рендеринг и добавляет оптимистическую строку, второй косвенно также запускает denormalizeEvent, который не имеет более оптимистичного флага и вернет первый добавил событие из истории и, следовательно, вернул оптимистическую строку и вместо этого добавил реальную с дополнительной информацией о файле.   -  person Robin F.    schedule 06.03.2017
comment
Давайте продолжим обсуждение в чате.   -  person SH-    schedule 06.03.2017
comment
Я бы попробовал поставить короткую задержку в createDocument между выполнением действия denormalizeEvent и разветвлением на executeDocumentUpload.   -  person Patrick Hund    schedule 07.03.2017
comment
@PatrickHund только что попробовал, не получилось.   -  person Robin F.    schedule 07.03.2017


Ответы (1)


Проблема заключалась в том, что я отправил файл в виде строки кодировки base64 и настроил запрос с неправильным типом содержимого.

'Content-Type': 'text/plain;charset=UTF-8'

помещение файла в объект FormData и отправка запроса без указанного типа содержимого приводят к неблокирующему запросу.

person Robin F.    schedule 08.03.2017