Await fetch(file_url) иногда возвращает не полное содержимое файла

У меня есть следующий код javascript для извлечения и обработки содержимого файла .csv.

async function fetchCsv() {
    const response = await fetch("levels.csv");
    const reader = response.body.getReader();
    const result = await reader.read();
    const decoder = new TextDecoder("utf-8");
    const csv = await decoder.decode(result.value);
    return csv;
}

    useEffect(() => {
        fetchCsv().then((csv) => {
            // process csv
                (...)

При запуске этого кода в 99% случаев переменная csv содержит правильное содержимое файла, но в редких случаях переменная csv представляет собой только усеченную часть фактического файла.

В чем может быть причина и как улучшить код, чтобы справиться с этим?

Это в приложении React, если это уместно.

Дополнительная информация:

  • Я убедился, что при возникновении проблемы сетевой ответ для файла level.csv является правильным ответом (возвращается 200 и полные 38 КБ)

Отвечает ли это на ваш вопрос? Получение текста из объекта ответа Fetch

SuperStormer 31.01.2023 22:44

Я не думаю, что это дубликат этого вопроса. Этот вопрос фокусируется на том, как вообще понять объект ответа на выборку. Этот вопрос, кажется, правильно использует выборку, хотя, вероятно, есть какая-то ошибка. Мне нужно разобраться, как fetch работает с фрагментированными кодировками или результатами, отличными от 200, и даже, возможно, с ошибками на стороне сервера.

Sam Hartman 31.01.2023 22:49

это один и тот же CSV-файл каждый раз или каждый раз другой CSV-файл?

YK1 31.01.2023 23:11

это всегда один и тот же csv, размещенный статически

Kuba 31.01.2023 23:14

Вы в состоянии детерминистически воспроизвести? если это так, прикрепите скрипач и посмотрите, есть ли проблема в самом ответе. Это может помочь изолировать проблемную область.

YK1 31.01.2023 23:49
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
5
90
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

При вызове response.body.getReader() вы получаете объект ReadableStreamDefaultReader.

Вызов его метода .read() вернет Promise, который будет разрешаться либо с полным содержимым тела ответа, если запрос был выполнен достаточно быстро, а размер тела не слишком велик (очевидно, 256 МБ в Firefox). , или только с одним фрагментом тела ответа.
Это позволяет вам обрабатывать ответ как поток, прежде чем он будет полностью извлечен.

Если вы хотите обработать этот поток как текст, вы можете использовать TextDecoderStream, который, наконец, получил поддержку во всех основных браузерах:

const response = await fetch("levels.csv");
const textStream = response.body.pipeThrough(new TextDecoderStream());
// now you can handle each chunk as text from textStream.getReader();
// or pipe it in yet another TransformStream

или в более олдскульном стиле, вы можете использовать опцию { stream: true } метода TextDecoder#decode() и обрабатывать там каждый фрагмент один за другим:

const response = await fetch("levels.csv");
const decoder = new TextDecoder();
const reader = response.body.getReader();
while (true) {
  const {value, done} = await reader.read();
  if (value) {
    csv_chunks.push(decoder.decode(value, {stream: true}));
    // do something with all the chunks we have so far
  }
  if (done) {
    break;
  }
}

Но, возможно, вы вообще не хотите обрабатывать этот ответ как поток, и в этом случае вам вполне может быть достаточно попросить браузер сначала получить все тело ответа, прежде чем он сам декодирует его как текст. Для этого, если вам нужно декодировать текст как UTF-8, вы должны использовать метод Response#text():

const response = await fetch("levels.csv");
if (!response.ok) { // don't forget to handle possible network errors
  throw new Error("NetworkError");
}
return response.text();

И если вам нужно обработать другую кодировку, то сначала используйте ответ как ArrayBuffer, а затем декодируйте его в текст:

const response = await fetch("levels.csv");
if (!response.ok) { // don't forget to handle possible network errors
  throw new Error("NetworkError");
}
const buf = await response.arrayBuffer();
const decoder = new TextDecoder(encoding);
return decoder.decode(buf);

Спасибо! Поскольку файл ASCII и никогда не будет больше нескольких сотен КБ, мне достаточно reponse.text(). кажется, что проблема исчезла (или, по крайней мере, вероятно, учитывая недетерминированный характер воспроизведения)

Kuba 01.02.2023 09:48

Другие вопросы по теме