取得进度指标?
我正在努力寻找使用fetch实现上传进度指示器的文档或示例。
这是迄今为止我发现的唯一参考 ,其中指出:
进度事件是一个高级function,现在不会到达提取。 您可以通过查看
Content-Length
标题并使用传递stream来监视接收到的字节来创build自己的。这意味着你可以明确地处理没有
Content-Length
回应。 当然,即使Content-Length
在那里,也可能是一个谎言。 随着stream你可以处理这些谎言,但是你想要的。
我将如何写“传递stream来监控字节”发送? 如果它有什么不同,我试图做到这一点,从浏览器的图像上传到Cloudinary 。
注意 :我对Cloudinary JS库 不感兴趣,因为它依赖于jQuery,我的应用程序不支持。 我只对使用原生javascript和Github的fetch
polyfill进行处理所需的stream处理感兴趣。
https://fetch.spec.whatwg.org/#fetch-api
数据stream开始登陆networking平台( https://jakearchibald.com/2016/streams-ftw/ ),但现在还处于初期阶段。
很快你就可以提供一个stream作为请求的主体,但是这个问题的关键是这个stream的消耗是否与上传的字节有关。
特定的redirect可能会导致数据重新传输到新的位置,但是stream不能“重新启动”。 我们可以通过将主体转换为可以多次调用的callback来解决这个问题,但是我们需要确保暴露redirect的数量不是安全漏洞,因为这将是平台上的第一次JS可以检测到。
有人质疑将stream消费链接到上传的字节是否有意义。
长话短说:这是不可能的,但在将来,这将通过stream,或某种更高级别的callback传递给fetch()
。
我不认为这是可能的。 草案指出:
当涉及到要求进展时,它目前缺乏[ 与XHR相比 ]
(老答案):
获取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,你可以使用Reader来逐字节地读取数据,你可以触发一个事件或者做任何你喜欢的事情(比如logging进度)他们每个人。
然而, Streams规范似乎并没有完成,我不知道这是否已经在任何提取实现工作。
由于没有任何答案可以解决问题。
只是为了实现,你可以用已知大小的一小块初始块来检测上传速度,上传时间可以用内容长度/上传速度来计算。 您可以使用这个时间作为估计。
一个可能的解决方法是利用new Request()
构造函数,然后检查Request.bodyUsed
Boolean
属性
bodyUsed
属性的getter必须返回true,否则返回false。
以确定stream是否distributed
如果
body
是非零的,并且它的stream
被disturbed
那么实现Body
mixin的对象被认为是被disturbed
。
当Request.bodyUsed
等于true
时,将.read()
的fetch()
Promise
返回链接到ReadableStream
recursion.read()
调用。
请注意,该方法不会读取Request.body
的字节,因为字节将stream式传输到端点。 而且,在任何响应全部返回给浏览器之前,上传可以完成。
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)); }
关键部分是ReadableStream < obj_response .body&gt ;.
样品:
let parse=_/*result*/=>{ console.log(_) //... return /*cont?*/_.value?true:false } fetch(''). then(_=>( a/*!*/=_.body.getReader(), b/*!*/=z=>a.read().then(parse).then(_=>(_?b:z=>z)()), b() ))
你可以testing在一个巨大的页面上运行,例如https://html.spec.whatwg.org/和https://html.spec.whatwg.org/print.pdf 。 CtrlShiftJ并加载代码。
(在Chrome上testing)