How to write javascript in client side to receive and parse `chunked` response in time?
I'm using play framework, to generate chunked response. The code is:
class Test extends Controller {
public static void chunk() throws InterruptedException {
for (int i = 0; i < 10; i++) {
String data = repeat("" + i, 1000);
response.writeChunk(data);
Thread.sleep(1000);
}
}
}
When I use browser to visit http://localhost:9000/test/chunk
, I can see the data displayed increased every second. But, when I write a javascript function to receive and handle the data, found it will block until all data received.
The code is:
$(function(){
$.ajax(
"/test/chunked",
{
"success": function(data, textStatus, xhr) {
alert(textStatus);
}
}
);
});
I can see a message box popped up after 10s, when all the data received.
How to get the stream and handle the data in time?
Solution 1:
jQuery doesn't support that, but you can do that with plain XHR:
var xhr = new XMLHttpRequest()
xhr.open("GET", "/test/chunked", true)
xhr.onprogress = function () {
console.log("PROGRESS:", xhr.responseText)
}
xhr.send()
This works in all modern browsers, including IE 10. W3C specification here.
The downside here is that xhr.responseText
contains an accumulated response. You can use substring on it, but a better idea is to use the responseType attribute and use slice
on an ArrayBuffer
.
Solution 2:
Soon we should be able to use ReadableStream
API (MDN docs here). The code below seems to be working with Chrome Version 62.0.3202.94:
fetch(url).then(function (response) {
let reader = response.body.getReader();
let decoder = new TextDecoder();
return readData();
function readData() {
return reader.read().then(function ({value, done}) {
let newData = decoder.decode(value, {stream: !done});
console.log(newData);
if (done) {
console.log('Stream complete');
return;
}
return readData();
});
}
});