I need to use xmlHTTPRequest to fetch data from an endless motion JPEG data stream, and I heard that a nice trick that the responseText
can populate data without finishing the request (it will never finish). Now I run into problem.
My request is bind with RxJS observable like this.
postActionGivenDataBinaryStream(url:string, data:string) : Observable<any>{
this.binary_progress_call_accum = 0 ;
this.previous_length = 0 ;
return Observable.create((observer)=>{
let xhr = new XMLHttpRequest() ;
xhr.open('POST',url,true) ;
xhr.setRequestHeader("Content-Type","application/json;charset=utf-8");
//this way the binary data keeps populate at state 3
xhr.overrideMimeType('text\/plain; charset=x-user-defined');
xhr.onreadystatechange = () =>{
if (xhr.readyState === 4) {
if (xhr.status === 200) {
this.binary_progress_call_accum = 0 ;
this.previous_length = 0 ;
observer.complete();
} else {
this.binary_progress_call_accum = 0 ;
this.previous_length = 0 ;
observer.error(xhr.response);
}
}
}
xhr.onprogress = (event)=>{
let outstring:string = "";
//should preordically emit the response text
if (this.binary_progress_call_accum > 1) {
//just send the next piece of data
let endCount = xhr.responseText.length ;
//so here try to next a string
for (let i = this.previous_length ; i < endCount; ++i ){
outstring += ("00" + (xhr.responseText.charCodeAt(i) & 0xFF).toString(16)).slice(-2) ;
}
observer.next(outstring) ;
this.previous_length = endCount ;
}
else{
for (let i = 0 ; i < xhr.responseText.length; ++i ){
outstring += ("00" + (xhr.responseText.charCodeAt(i) & 0xFF).toString(16)).slice(-2) ;
}
observer.next(outstring) ;
this.previous_length = xhr.responseText.length ;
}
this.binary_progress_call_accum += 1;
};
xhr.send(data) ;
//https://stackoverflow.com/a/38622923/921082
//elegantly abort()
return () => xhr.abort() ;
}) ;
}
But this piece of code has serious problem, I call this observable at a 30 seconds interval, but, it sometimes stuck. When my interval observable triggered, the request just delay for 30 seconds! Without doing anything, the console log gives nothing.
I suspect that it's the xhr.abort() takes too long to finish, before it finishes, the interval observable gives next request, which will conflict with the previous one, which causes the request-response delay. So is there any way to release the memory of responseText
without using interval to reinit such xhr request observable?
This seems a tough one, I actually solved it.
The answer has nothing to do with my code above, but the code calls this request observable.
I should use
repeatWhen
instead ofIntervalObservable
. SinceIntervalObservable
doesn't care if the request actually complete or not, it will cause request triggered before last one complete. WhereasrepeatWhen
ensures the last observable actually complete before the next start.Please check this enlighten discussion, https://github.com/ReactiveX/RxJava/issues/448