【问题标题】:Angular 2 , value returned before function completeAngular 2,函数完成前返回的值
【发布时间】:2021-04-06 14:29:03
【问题描述】:

在我的 Angular 中,我有一项服务可以在画布上绘制图片并获取其“ImageData”。

这是我的 service.ts:

getColorArray (movie: MovieDb): Observable<any> {
    var img = new Image();
    img.crossOrigin = "Anonymous";
    img.src = "https://www.themoviedb.org/t/p/w342/" + movie.poster;
    var canvas = <HTMLCanvasElement>document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    canvas.height = 50;
    canvas.width = 30;
    ctx.clearRect(0, 0, canvas.width, canvas.height); 
    ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
    var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    return of(imgData)
  }

还有我使用它的 .ts:

pixelate(movie) {
    this.getBackgroundColor.getColorArray(movie)
    .subscribe(r => do something with r)

我已经把它作为一个 Observable 认为 imgData 将在 getImageData() 完成时返回,但它会在 getColorArray() 被调用时立即返回。 我如何等待getImageData() 完成后再返回其值?

【问题讨论】:

  • getImageData() 不是异步 API。我的猜测是你还有另一个错误。

标签: angular asynchronous promise observable


【解决方案1】:

问题不是“等待getImageData”,而是等待图像加载,您需要明确地这样做。类似:

getColorArray (movie: MovieDb): Observable<any> {
  // create an observable
  return new Observable(obs => {
    var img = new Image();
    img.crossOrigin = "Anonymous";
    img.src = "https://www.themoviedb.org/t/p/w342/" + movie.poster;
    
    // once the image loads, draw it and the image data is available synchronously
    var imgLoadListener = e => {
      var canvas = <HTMLCanvasElement>document.getElementById("canvas");
      var ctx = canvas.getContext("2d");
      canvas.height = 50;
      canvas.width = 30;
      ctx.clearRect(0, 0, canvas.width, canvas.height); 
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
      var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
      obs.next(imgData);
      obs.complete();
    };

    img.addEventListener('load', imgLoadListener);
    
    return () => { // clean up after yourself.
      img.removeEventListener('load', imgLoadListener)
    }
  })
}

使用deferfromEvent 的一种更清洁/更少手动的方法是这样,它们将为您处理一些清理工作并更好地处理错误:

getColorArray (movie: MovieDb): Observable<any> {
  // defer to not create image until subscribe
  return defer(() => {
    var img = new Image();
    img.crossOrigin = "Anonymous";
    img.src = "https://www.themoviedb.org/t/p/w342/" + movie.poster;
    
    return fromEvent(img, 'load').pipe(
      map(() => {
        var canvas = <HTMLCanvasElement>document.getElementById("canvas");
        var ctx = canvas.getContext("2d");
        canvas.height = 50;
        canvas.width = 30;
        ctx.clearRect(0, 0, canvas.width, canvas.height); 
        ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
        var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        return imgData;
      })
    ); 
  })
}

您可以删除上面的 defer 部分,它会正常工作,但在 observables 中的标准做法是确保它们在订阅之前什么都不做,defer 的使用在这里完成。

【讨论】:

  • 完美运行,现在我必须弄清楚 fromEvent() 以便将来使用它:)
  • 只是从 DOM 元素事件中创建 observables
  • 但是我的 img 不在 DOM 中,不是吗?
  • 它没有附加到您当前的文档中,但它仍然是一个 DOM 元素。 new Image() 只是 document.createElement('img') 的更漂亮的简写
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-20
  • 2021-12-02
  • 2017-10-17
  • 2018-02-08
  • 1970-01-01
相关资源
最近更新 更多