如何在角度rxjs订阅调用中执行嵌套的JavaScript库Promise回调

时间:2020-07-10 06:10:51

标签: javascript angular html2canvas angular9 zone

每当发生错误时,我都有一个要求,我需要收集基本的错误跟踪,IP地址和屏幕截图。

对于Ip地址,我正在使用此API来获取IP地址。 getIp:“ http://api.ipify.org/?format=json”。 对于使用Html2 Canvas的ScreenShot:库:https://github.com/niklasvh/html2canvas/issues/2282。

这是发生错误时触发的方法。

我添加了一个wait,但是它不等待回调的响应,它会在执行回调之前返回。

初始呼叫

getIP(response:any)
  {
// call 1
    this.getIPAddress().subscribe(async(res:any)=>{ 
    this.ipAddress = res.ip;  
// get an ip once ip recieved call another function


    let errorRequest =  await this.logError(response); call 2
// another service call
    this.logErrorRequest(errorRequest); //  send another service call to server to store the error
    });

    return  errorDetails;
  } 

此方法中的第二个调用..格式化请求。在这里获取屏幕截图,我需要调用javascript库html2canvas。等待this.getScreenShot()

//问题在于,该方法将在从该promise调用获得响应之前返回响应。

async logError(response:any):ErrorRequest{
    error={
        ExceptionMessage:response.message,
        ipAddress:this.ipAddress,
        screenShot:await this.getScreenShot()    // next call 3.
    };
   
    return error;
}

//答应回电

async getScreenShot() {
    this.zone.runOutsideAngular(() => {
// call 4
      html2canvas(document.querySelector("#capture")).then(canvas => {
      canvas.toBlob(function(blob){
                let link = document.createElement("a");
                link.download = "image.png";
                link.href = URL.createObjectURL(blob);
                link.click();
                let screenShot = blob; 
                 this.screenShot = blob;

            },'image/png');

   
         //your code
      })   

    });

1 个答案:

答案 0 :(得分:0)

除了getScreenShot()之外,您没有从Promise<void>返回任何信息,但这仅仅是因为async。还感觉前两个调用并不相互依赖,因此您可以并行执行它们:

这意味着,要解决您的问题,您需要重构getScreenShot()方法:

getScreenShot() {
  return this.zone.runOutsideAngular(async () => {
    const canvas = await html2canvas(document.getElementById("capture"));

    return new Promise(
      (resolve) => canvas.toBlob((blob) => resolve(blob), 'image/png')
    );
  });
}

简而言之,返回this.zone调用,等待html2canvas调用,创建一个新的Promise并以您的决心返回。另外,请勿使用function关键字,因为那样会弄乱this上下文。


更长的修复程序需要重构代码,看起来像这样:

logError(response: { message: string }): void {
  forkJoin([
    this.getIPAddress(),
    this.getScreenShot()
  ]).pipe(
    concatMap(([ { ip }, screenshot ]) => this.logErrorRequest({
      ExceptionMessage: response.message,
      ipAddress: ip,
      screenshot
    }))
  ).subscribe({
    next: () => console.log('error logged'),
    error: () => console.log('make sure to catch this to prevent loop!')
  });
}

这显然将使用重构的getScreenShot方法。如您所见,这更加清楚了,并且避免了使用随机this分配。就像rxjs想要的东西一样,这是一个很好的流。

还要确保以某种方式对错误日志进行去抖动/分组,以防止错误泛滥或无限循环。相信我,它发生了:D