如何从Observable中止Ajax请求?

时间:2016-07-27 16:38:58

标签: javascript ajax typescript rxjs observable

我的代码包含我用来将文件上传到我的PHP服务器的简单函数(嵌套在xhr中的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.complete();
                }
            }
        };

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

它完全正常运行但现在我还想为它添加某种取消机制。

只是取消订阅Observable是行不通的,因为我需要以某种方式致电xhr.abort()或者浪费宝贵的资源进行大量上传。

是否可以通过修改此代码来获得优雅的解决方案,或者我做错了因为我正在使用RxJS/Observable执行此任务?

3 个答案:

答案 0 :(得分:7)

创建Observable时,您可以通过从构建器函数返回Subscriptionfunction来指定取消订阅行为:

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.complete();
                } 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 completed
        //Since this gets called in all cases when the `Subscription` terminates
        return () => xhr.abort();
    });
}

答案 1 :(得分:1)

返回xhr对象并在另一个observable中对其执行abort。

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');
  });

或者

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

答案 2 :(得分:0)

请求将中止进入取消订阅的呼叫。 有关更多详细信息,请参见AjaxObservable.unsubscribe来源: https://github.com/ReactiveX/rxjs/blob/441d52208df8b9247b01f8ca3993e3a7b0870b10/src/internal/observable/dom/AjaxObservable.ts#L423