У меня есть следующий код 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, если это уместно.
Дополнительная информация:
Я не думаю, что это дубликат этого вопроса. Этот вопрос фокусируется на том, как вообще понять объект ответа на выборку. Этот вопрос, кажется, правильно использует выборку, хотя, вероятно, есть какая-то ошибка. Мне нужно разобраться, как fetch работает с фрагментированными кодировками или результатами, отличными от 200, и даже, возможно, с ошибками на стороне сервера.
это один и тот же CSV-файл каждый раз или каждый раз другой CSV-файл?
это всегда один и тот же csv, размещенный статически
Вы в состоянии детерминистически воспроизвести? если это так, прикрепите скрипач и посмотрите, есть ли проблема в самом ответе. Это может помочь изолировать проблемную область.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


При вызове 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(). кажется, что проблема исчезла (или, по крайней мере, вероятно, учитывая недетерминированный характер воспроизведения)
Отвечает ли это на ваш вопрос? Получение текста из объекта ответа Fetch