fetch를 사용하여 업로드 진행률 표시기를 구현하는 문서 또는 예제를 찾는 데 어려움을 겪고 있습니다 .
이것은 내가 지금까지 찾은 유일한 참조 이며 다음과 같습니다.
진행 이벤트는 지금은 가져 오지 않는 고급 기능입니다.
Content-Length
헤더 를보고 통과 스트림을 사용하여 수신 된 바이트를 모니터링 하여 직접 만들 수 있습니다 .즉,
Content-Length
다르게 하지 않고 명시 적으로 응답을 처리 할 수 있습니다 . 물론Content-Length
거기 있어도 거짓말이 될 수 있습니다. 스트림을 사용하면 이러한 거짓말을 원하는대로 처리 할 수 있습니다.
전송 된 “바이트를 모니터링하기위한 통과 스트림”을 어떻게 작성합니까? 어떤 종류의 차이가 있다면 브라우저에서 Cloudinary로 이미지 업로드를 강화 하기 위해이 작업을 수행하려고합니다 .
참고 : Cloudinary JS 라이브러리 에는 관심 이 없습니다. jQuery에 의존하고 내 앱에는 그렇지 않기 때문입니다. 네이티브 자바 스크립트와 Github의 폴리 필로 이를 수행하는 데 필요한 스트림 처리에만 관심이 있습니다.fetch
답변
스트림이 웹 플랫폼 ( https://jakearchibald.com/2016/streams-ftw/ ) 에 착륙하기 시작 했지만 아직 초기 단계입니다.
곧 요청 본문으로 스트림을 제공 할 수있게 될 것이지만 공개 된 질문은 해당 스트림의 소비가 업로드 된 바이트와 관련이 있는지 여부입니다.
특정 리디렉션으로 인해 데이터가 새 위치로 재전송 될 수 있지만 스트림은 “다시 시작”할 수 없습니다. 본문을 여러 번 호출 할 수있는 콜백으로 변환하여이 문제를 해결할 수 있지만 리디렉션 수를 노출하는 것이 보안 누출이 아닌지 확인해야합니다. JS 플랫폼에서는 처음 일 수 있기 때문입니다. 그것을 감지하십시오.
일부는 스트림 소비를 업로드 된 바이트에 연결하는 것이 합리적 일지 의문을 제기합니다.
간단히 말해서 : 아직 불가능하지만 앞으로는 스트림이나 .NET에 전달 된 일종의 상위 수준 콜백에 의해 처리 될 것 fetch()
입니다.
답변
내 해결책은 이것을 매우 잘 지원 하는 axios 를 사용 하는 것입니다.
axios.request( {
method: "post",
url: "/aaa",
data: myData,
onUploadProgress: (p) => {
console.log(p);
//this.setState({
//fileprogress: p.loaded / p.total
//})
}
}).then (data => {
//this.setState({
//fileprogress: 1.0,
//})
})
답변
나는 그것이 가능하다고 생각하지 않는다. 초안은 다음과 같이 설명합니다.
요청 진행 과 관련하여 현재 [ XHR에 비해 ] 부족합니다.
(이전 답변) : Fetch API 장의
첫 번째 예는 다음 방법에 대한 통찰력을 제공합니다.
신체 데이터를 점진적으로 수신하려는 경우 :
function consume(reader) { var total = 0 return new Promise((resolve, reject) => { function pump() { reader.read().then(({done, value}) => { if (done) { resolve() return } total += value.byteLength log(`received ${value.byteLength} bytes (${total} bytes in total)`) pump() }).catch(reject) } pump() }) } fetch("/music/pk/altes-kamuffel.flac") .then(res => consume(res.body.getReader())) .then(() => log("consumed the entire body without keeping the whole thing in memory!")) .catch(e => log("something went wrong: " + e))
그렇다의 사용에서 Promise
생성자 안티 패턴 , 당신은 볼 수 response.body
당신이 리더를 사용하여 바이트로 바이트를 읽을 수있는 Stream에, 당신은 이벤트를 발생 또는 같은 당신이 무엇을 그들 모두를 위해 (예 : 진행 상황을 기록) 할 수 있습니다.
그러나 Streams 사양 은 아직 완성되지 않은 것으로 보이며이 기능 이 이미 모든 가져 오기 구현에서 작동하는지 여부는 알 수 없습니다.
답변
업데이트 : 받아 들여진 대답에 따르면 지금은 불가능합니다. 그러나 아래 코드는 언젠가 문제를 처리했습니다. 최소한 XMLHttpRequest를 기반으로하는 라이브러리를 사용하도록 전환해야한다는 점을 추가해야합니다.
const response = await fetch(url);
const total = Number(response.headers.get('content-length'));
const reader = response.body.getReader();
let bytesReceived = 0;
while (true) {
const result = await reader.read();
if (result.done) {
console.log('Fetch complete');
break;
}
bytesReceived += result.value.length;
console.log('Received', bytesReceived, 'bytes of data so far');
}
이 링크 덕분에 : https://jakearchibald.com/2016/streams-ftw/
답변
답변 중 어느 것도 문제를 해결하지 못하기 때문입니다.
구현을 위해 알려진 크기의 작은 초기 청크로 업로드 속도 를 감지 할 수 있으며 업로드 시간은 content-length / upload-speed로 계산할 수 있습니다. 이 시간을 추정치로 사용할 수 있습니다.
답변
가능한 해결 방법은 new Request()
생성자 를 활용 한 다음 Request.bodyUsed
Boolean
속성 을 확인하는 것입니다.
bodyUsed
속성의 게터는 경우 true를 반환해야한다disturbed
, 그렇지 않으면 거짓.
스트림인지 확인하려면 distributed
Body
믹스 인을 구현하는 객체 는disturbed
if
body
is non-null이고stream
is라고disturbed
합니다.
이 같을 때 의 재귀 호출에 연결된 fetch()
Promise
내부에서를 반환합니다 ..then()
.read()
ReadableStream
Request.bodyUsed
true
이 접근 방식은 Request.body
바이트가 끝점으로 스트리밍되므로의 바이트를 읽지 않습니다 . 또한 브라우저에 응답이 모두 반환되기 전에 업로드가 완료 될 수 있습니다.
const [input, progress, label] = [
document.querySelector("input")
, document.querySelector("progress")
, document.querySelector("label")
];
const url = "/path/to/server/";
input.onmousedown = () => {
label.innerHTML = "";
progress.value = "0"
};
input.onchange = (event) => {
const file = event.target.files[0];
const filename = file.name;
progress.max = file.size;
const request = new Request(url, {
method: "POST",
body: file,
cache: "no-store"
});
const upload = settings => fetch(settings);
const uploadProgress = new ReadableStream({
start(controller) {
console.log("starting upload, request.bodyUsed:", request.bodyUsed);
controller.enqueue(request.bodyUsed);
},
pull(controller) {
if (request.bodyUsed) {
controller.close();
}
controller.enqueue(request.bodyUsed);
console.log("pull, request.bodyUsed:", request.bodyUsed);
},
cancel(reason) {
console.log(reason);
}
});
const [fileUpload, reader] = [
upload(request)
.catch(e => {
reader.cancel();
throw e
})
, uploadProgress.getReader()
];
const processUploadRequest = ({value, done}) => {
if (value || done) {
console.log("upload complete, request.bodyUsed:", request.bodyUsed);
// set `progress.value` to `progress.max` here
// if not awaiting server response
// progress.value = progress.max;
return reader.closed.then(() => fileUpload);
}
console.log("upload progress:", value);
progress.value = +progress.value + 1;
return reader.read().then(result => processUploadRequest(result));
};
reader.read().then(({value, done}) => processUploadRequest({value,done}))
.then(response => response.text())
.then(text => {
console.log("response:", text);
progress.value = progress.max;
input.value = "";
})
.catch(err => console.log("upload error:", err));
}
답변
const req = await fetch('./foo.json');
const total = Number(req.headers.get('content-length'));
let loaded = 0;
for await(const {length} of req.body.getReader()) {
loaded = += length;
const progress = ((loaded / total) * 100).toFixed(2); // toFixed(2) means two digits after floating point
console.log(`${progress}%`); // or yourDiv.textContent = `${progress}%`;
}