Angular 2 , 函数完成前的返回值
Angular 2 , value returned before function complete
在我的 Angular 中,我有一项服务可以在 canvas 上绘制图片并获取其“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
”,而是等待图像加载,您需要明确地执行此操作。类似于:
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)
}
})
}
一种更清洁/更少手动操作的方法是这样,使用 defer
和 fromEvent
,这将为您处理一些清理工作并更好地处理错误:
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
完成这里。
在我的 Angular 中,我有一项服务可以在 canvas 上绘制图片并获取其“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
”,而是等待图像加载,您需要明确地执行此操作。类似于:
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)
}
})
}
一种更清洁/更少手动操作的方法是这样,使用 defer
和 fromEvent
,这将为您处理一些清理工作并更好地处理错误:
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
完成这里。