使用Angular 4如何在observable中进行http promise调用?

时间:2017-12-16 03:00:14

标签: javascript angular amazon-web-services observable aws-api-gateway

使用Angular 4如何在Observable中进行http promise调用?我正在使用AWS API Gateway和Cognito Federated帐户。我们必须使用apigClient.invokeApi来签署每个http调用。我想得到promise调用的结果,并将结果作为一个observable返回。下面的代码触发,但根本没有得到其余的可观察代码。当我订阅observable时,它永远不会访问subscribe中的代码。我也没有得到任何编译错误。任何帮助都会有所帮助。

public upload(image, fileType): Observable<FileReturnData> {
  const apigClient = apigClientFactory.newClient({
    accessKey: this.auth.cognitoAccessKey,
    secretKey: this.auth.cognitoSecretKey,
    sessionToken: this.auth.cognitoSessionToken,
    invokeUrl: this.auth.URL
  });
  const data = new FileData()
  data.image = image;
  data.fileType = fileType;
  const uploadPromise = apigClient.invokeApi({}, '/users/upload', 'POST', {}, {image: image, fileType: fileType});


const observable = new Observable<FileReturnData>(observer => {

    uploadPromise.then(function (uploadResult) {
      console.log(uploadResult); // I see this in the console

      const fileReturnData = new FileReturnData();

      const responseBody = JSON.parse(uploadResult.body);

      fileReturnData.filename = responseBody.filename;
      console.log('IN OBSERVABLE');  //  I never get to this result
      observer.next(fileReturnData);
      observer.complete();


      return () => console.log('upload image user observable disposed');

    }).catch(function (uploadImageError) {

      return () => console.error(uploadImageError);
    });

  });

  return observable;

}

1 个答案:

答案 0 :(得分:0)

我只对这样的Ajax调用使用嵌套的promises但我相信你的代码问题,使用observables和嵌套的promise是你过早地启动了invokeApi http调用,调用/users/upload当你期望它时没有完成,因此upload等待观察者完成()返回的观察者的订阅者将会产生意想不到的后果,因为你在observer.complete()中调用uploadPromise.then可能有已经完成或我尚未完成。

看看这是否修复了您的代码:

  public upload(image, fileType): Observable<FileReturnData> {
      const apigClient = apigClientFactory.newClient({
        accessKey: this.auth.cognitoAccessKey,
        secretKey: this.auth.cognitoSecretKey,
        sessionToken: this.auth.cognitoSessionToken,
        invokeUrl: this.auth.URL
      });

    const observable = new Observable<FileReturnData>(observer => {

        const data = new FileData()
        data.image = image;
        data.fileType = fileType;

        apigClient.invokeApi({}, '/users/upload', 'POST', {}, {image: image, fileType: fileType})
        .then(function (uploadResult) {
          console.log(uploadResult); // I see this in the console

          const fileReturnData = new FileReturnData();

          const responseBody = JSON.parse(uploadResult.body);

          fileReturnData.filename = responseBody.filename;
          console.log('IN OBSERVABLE');  //  I never get to this result
          observer.next(fileReturnData);
          observer.complete();

        }).catch(function (uploadImageError) {

          //handle error
        });

      });

      return observable;

    }

如果我完全理解你的场景,我个人觉得使用嵌套的http调用更容易管理。这是您可以使用的代码版本,仅使用promises,然后任何Observable都可以调用upload并等待其完成:

  public upload(image, fileType): Promise<FileReturnData> {
      const apigClient = apigClientFactory.newClient({
        accessKey: this.auth.cognitoAccessKey,
        secretKey: this.auth.cognitoSecretKey,
        sessionToken: this.auth.cognitoSessionToken,
        invokeUrl: this.auth.URL
      });



    const promise = new Promise<FileReturnData>((resolve, reject) => {

        const data = new FileData()
        data.image = image;
        data.fileType = fileType;
        //I moved this "invokeApi" call here because it does not seem like a factory method
        //it seems like you start an ajax call when "invokeApi" is called
        //so you must keep this all within the promise you are returning to callers
        //of the upload function
        apigClient.invokeApi({}, '/users/upload', 'POST', {}, {image: image, fileType: fileType})
        .then(uploadResult => {
          console.log(uploadResult); // I see this in the console

          const fileReturnData = new FileReturnData();

          const responseBody = JSON.parse(uploadResult.body);

          fileReturnData.filename = responseBody.filename;

          resolve(fileReturnData);

        }, msg => {
            reject(msg);
        }).catch(ex => {
          return () => console.error(ex);
        });

      });

      return promise;

    }