admin管理员组

文章数量:1312783

My code contains this simple function I'm using to upload files to my PHP server (there's an xhr request nested in an RxJS/Observable):

fileUpload(file: File): Observable<any> {
    return new Observable( observer => {
        let xhr:XMLHttpRequest = new XMLHttpRequest();
        xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    observer.next(<any>JSON.parse(xhr.response));
                } else {
                    observer.error(xhr.response);
                    observerplete();
                }
            }
        };

        xhr.open('POST', '__BACKEND__?action=file-upload', true);
        var formData = new FormData();
        formData.append('file', file, file.name);
        xhr.send(formData);
    });
}

It is pletely functional but now I would also like to add some sort of a cancellation mechanic to it.

Just unsubscribing from the Observable won't work, because I need to somehow call xhr.abort() or I waste precious resources with large uploads.

Is it possible to get an elegant solution by modifying this code or am I doing it wrong because I'm using an RxJS/Observable for this task?

My code contains this simple function I'm using to upload files to my PHP server (there's an xhr request nested in an RxJS/Observable):

fileUpload(file: File): Observable<any> {
    return new Observable( observer => {
        let xhr:XMLHttpRequest = new XMLHttpRequest();
        xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    observer.next(<any>JSON.parse(xhr.response));
                } else {
                    observer.error(xhr.response);
                    observer.plete();
                }
            }
        };

        xhr.open('POST', '__BACKEND__?action=file-upload', true);
        var formData = new FormData();
        formData.append('file', file, file.name);
        xhr.send(formData);
    });
}

It is pletely functional but now I would also like to add some sort of a cancellation mechanic to it.

Just unsubscribing from the Observable won't work, because I need to somehow call xhr.abort() or I waste precious resources with large uploads.

Is it possible to get an elegant solution by modifying this code or am I doing it wrong because I'm using an RxJS/Observable for this task?

Share Improve this question asked Jul 27, 2016 at 16:38 Blaž ZupančičBlaž Zupančič 2,3562 gold badges14 silver badges22 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 9

When you create an Observable you can specify the unsubscribe behavior by returning a Subscription or a function from builder function:

fileUpload(file: File): Observable<any> {
    return new Observable( observer => {
        let xhr:XMLHttpRequest = new XMLHttpRequest();
        xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    observer.next(<any>JSON.parse(xhr.response));
                    observer.plete();
                } else {
                    observer.error(xhr.response);
                }
            }
        };

        xhr.open('POST', '__BACKEND__?action=file-upload', true);
        var formData = new FormData();
        formData.append('file', file, file.name);
        xhr.send(formData);

        //Return the tear down logic. 
        //You may also want to check here that it has not already pleted
        //Since this gets called in all cases when the `Subscription` terminates
        return () => xhr.abort();
    });
}

Return the xhr object and execute abort on it in a another observable.

var uploadObservable = fileUpload();
var uploadRequest;

uploadObservable.subscribe(
  function (x) {
    uploadRequest = x;
  },
  function (err) {
    console.log('Error: %s', err);
  },
  function () {
    console.log('Completed');
  });


var cancelBtn = Rx.Observable.fromEvent(cancelBtn, 'click');

cancelBtn.subscribe(
  function (x) {
    uploadRequest.abort();
  },
  function (err) {
    console.log('Error: %s', err);
  },
  function () {
    console.log('Completed');
  });

Or

 fileUpload()
    .flatMap(function(xhr) {
      Rx.Observable.fromEvent(cancelBtn, 'click').subscribe(function() {xhr.abort()})
    })
.subscribe(...);

Request will aborted into unsubscribe call. For more details, see AjaxObservable.unsubscribe sources: https://github./ReactiveX/rxjs/blob/441d52208df8b9247b01f8ca3993e3a7b0870b10/src/internal/observable/dom/AjaxObservable.ts#L423

本文标签: javascriptHow to abort an Ajax request from an ObservableStack Overflow