如何从xhr返回Observable

时间:2017-05-20 12:16:02

标签: angular rxjs observable reactive-programming

我有这样的功能,只需用xhr请求上传图片:

public uploadAvatar(avatarFile, callback) {
    return new Promise((resolve, reject) => {
      let formData: any = new FormData();
      let url = 'avatar';
      let imgArr = "avatar";
      let xhr = new XMLHttpRequest();

      formData.append(imgArr, avatarFile, avatarFile.name);
      xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
          if (xhr.status == 200) {
            resolve(JSON.parse(xhr.response));
            callback('success');
          } else {
            reject(xhr.response);
            callback('error');
          }
        }
      };

      xhr.open("POST", environment.baseUrl + url, true);
      xhr.setRequestHeader('Auth', this._auth.getToken());
      xhr.send(formData);
    });
  }

如何返回Observable insted Promise?

4 个答案:

答案 0 :(得分:2)

这样的事情应该有效

 public uploadAvatar(avatarFile, callback) {
    return Rx.Observable.create(function (observer) {
      let formData: any = new FormData();
      let url = 'avatar';
      let imgArr = "avatar";
      let xhr = new XMLHttpRequest();

      formData.append(imgArr, avatarFile, avatarFile.name);
      xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
          if (xhr.status == 200) {
            observer.onNext(JSON.parse(xhr.response));
            observer.onCompleted();
            callback('success');
          } else {
            observer.onError(xhr.response);
            callback('error');
          }
        }
      };

      xhr.open("POST", environment.baseUrl + url, true);
      xhr.setRequestHeader('Auth', this._auth.getToken());
      xhr.send(formData);
    });
}

答案 1 :(得分:2)

eddyP23的答案几乎正确,但还有两件事。

Observables和Promises之间的一个关键区别是,与Promises相比,Observable可以被取消。这与您使用XHR执行AJAX调用的情况非常相关。虽然可以使用abort() function中止XMLHttpRequest,但您无法中止待处理的Promise。

然而,对于Observables,你可以。当您完成或取消订阅Observable时,您也可以取消XHR对象,因为您知道自己对此不感兴趣。

另请参阅:https://medium.com/@benlesh/promise-cancellation-is-dead-long-live-promise-cancellation-c6601f1f5082

因此,当您使用Promises转换为Observable时,您的函数应如下所示:

public uploadAvatar(avatarFile, callback) {
    return Rx.Observable.create(function (observer) {
        ...
        xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                observer.onNext(JSON.parse(xhr.response));
                observer.onCompleted();
            } else {
                observer.onError(xhr.response);
            }
        }

        return () => {
            xhr.abort();
        };
    }
)

请注意,我们正在返回一个在处理Observable时使用的函数。有关Observable.create的更多信息,请查看http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-create

第二件事是,如果你不关心中止XHR,你可以使用Promises。 RxJS 5以与Observable相同的方式处理Promises。请注意,Observable.from()将参数ObservableInput作为参数,详细说明如下:http://reactivex.io/rxjs/class/es6/MiscJSDoc.js~ObservableInputDoc.html

对你而言,这意味着您可以按原样调用uploadAvatar(),并且返回的Promise将自动转换为Observables:

Observable.from(uploadAvatar(...))
    .subscribe(...)

答案 2 :(得分:0)

在你的Promise中使用fromPromise。请记住之前导入该方法,如

import 'rxjs/add/observable/fromPromise';

答案 3 :(得分:0)

简单方法如下:

xhrCall(url, formData, header) {
    return Observable.create(function (observer) {
      let xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
          if (xhr.status == 200) {
            observer.next(xhr);
          } else {
            observer.error(xhr);
          }
        }
      };

      xhr.open("POST", url, true);
      xhr.setRequestHeader(header.name, header.value);
      xhr.send(formData);
    });
}