我正在尝试在我们的服务器上启动一个长时间运行(10-30秒)的作业,并在不关闭连接的情况下监视它的进度。基本上,我上传了一个文件,并将进度传递回由换行符分隔的客户端。这是一个示例响应(每个换行延迟几毫秒):
01
23
48
60
73
87
96
我能够使用实验性的ReadableStream
和TextDecoder
apis来解决这个问题,但我正在寻找一种更符合浏览器的方式。这是我的代码:
fetch('/thing/').then(r => {
let reader = r.body.getReader('byob')
const doIt = () => {
reader.read().then(({done, value}) => {
value = new TextDecoder("utf-8").decode(value)
if (done) {
clearInterval(interval)
}
if (value) {
console.log(`${value}% done`)
}
})
}
const interval = setInterval(doIt, 10)
})
我已经尝试将XMLHttpRequest上的responseType设置为blob
和arraybuffer
,每隔毫秒检查一次响应,但无法获得流式传输;它会在完成后打印出完整的响应。
这是我提出的解决方案:
function monitorServerSentEvents(url, opts, onProgress) {
const headers = {'Content-Type': false, 'Accept': false}
return fetch(url, {headers, ...opts}).then(res => {
const reader = res.body.getReader('byob')
return new Promise((resolve, reject) => {
;(function readProgress() {
reader.read()
.catch(reject)
.then(({done, value}) => {
if (done) {
resolve()
}
if (!value) {
return
}
const decoder = (new TextDecoder("utf-8"))
const progress = decoder.decode(value).trim().split('\n')
progress.forEach(onProgress)
setTimeout(readProgress, 50)
})
}())
})
})
}
这仅适用于支持ReadableStream.getReader的浏览器。