How to release memory of the responseText in an en

2019-09-16 10:11发布

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?

1条回答
Juvenile、少年°
2楼-- · 2019-09-16 10:46

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 of IntervalObservable. Since IntervalObservable doesn't care if the request actually complete or not, it will cause request triggered before last one complete. Whereas repeatWhen ensures the last observable actually complete before the next start.

Please check this enlighten discussion, https://github.com/ReactiveX/RxJava/issues/448

查看更多
登录 后发表回答