From c437d43d3f04967b5a18cb9a918273af4f46c8f4 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Wed, 20 Dec 2023 11:47:06 +0100 Subject: [PATCH] ref: Avoid async in canvas (#143) Related to https://github.com/getsentry/rrweb/pull/142, noticed that this is kind of unnecessary (and is transpiled in pre-ES2017 envs). Passing an async function to forEach is anyhow a bit weird I'd say. --- .../record/observers/canvas/canvas-manager.ts | 96 ++++++++++--------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/packages/rrweb/src/record/observers/canvas/canvas-manager.ts b/packages/rrweb/src/record/observers/canvas/canvas-manager.ts index 76b20c6f76..4149860adb 100644 --- a/packages/rrweb/src/record/observers/canvas/canvas-manager.ts +++ b/packages/rrweb/src/record/observers/canvas/canvas-manager.ts @@ -232,52 +232,58 @@ export class CanvasManager implements CanvasManagerInterface { } lastSnapshotTime = timestamp; - getCanvas() - // eslint-disable-next-line @typescript-eslint/no-misused-promises - .forEach(async (canvas: HTMLCanvasElement) => { - const id = this.mirror.getId(canvas); - if (snapshotInProgressMap.get(id)) return; - - // The browser throws if the canvas is 0 in size - // Uncaught (in promise) DOMException: Failed to execute 'createImageBitmap' on 'Window': The source image width is 0. - // Assuming the same happens with height - if (canvas.width === 0 || canvas.height === 0) return; - - snapshotInProgressMap.set(id, true); - if (['webgl', 'webgl2'].includes((canvas as ICanvas).__context)) { - // if the canvas hasn't been modified recently, - // its contents won't be in memory and `createImageBitmap` - // will return a transparent imageBitmap - - const context = canvas.getContext((canvas as ICanvas).__context) as - | WebGLRenderingContext - | WebGL2RenderingContext - | null; - if ( - context?.getContextAttributes()?.preserveDrawingBuffer === false - ) { - // Hack to load canvas back into memory so `createImageBitmap` can grab it's contents. - // Context: https://twitter.com/Juice10/status/1499775271758704643 - // Preferably we set `preserveDrawingBuffer` to true, but that's not always possible, - // especially when canvas is loaded before rrweb. - // This hack can wipe the background color of the canvas in the (unlikely) event that - // the canvas background was changed but clear was not called directly afterwards. - // Example of this hack having negative side effect: https://visgl.github.io/react-map-gl/examples/layers - context.clear(context.COLOR_BUFFER_BIT); - } + getCanvas().forEach((canvas: HTMLCanvasElement) => { + const id = this.mirror.getId(canvas); + if (snapshotInProgressMap.get(id)) return; + + // The browser throws if the canvas is 0 in size + // Uncaught (in promise) DOMException: Failed to execute 'createImageBitmap' on 'Window': The source image width is 0. + // Assuming the same happens with height + if (canvas.width === 0 || canvas.height === 0) return; + + snapshotInProgressMap.set(id, true); + if (['webgl', 'webgl2'].includes((canvas as ICanvas).__context)) { + // if the canvas hasn't been modified recently, + // its contents won't be in memory and `createImageBitmap` + // will return a transparent imageBitmap + + const context = canvas.getContext((canvas as ICanvas).__context) as + | WebGLRenderingContext + | WebGL2RenderingContext + | null; + if ( + context?.getContextAttributes()?.preserveDrawingBuffer === false + ) { + // Hack to load canvas back into memory so `createImageBitmap` can grab it's contents. + // Context: https://twitter.com/Juice10/status/1499775271758704643 + // Preferably we set `preserveDrawingBuffer` to true, but that's not always possible, + // especially when canvas is loaded before rrweb. + // This hack can wipe the background color of the canvas in the (unlikely) event that + // the canvas background was changed but clear was not called directly afterwards. + // Example of this hack having negative side effect: https://visgl.github.io/react-map-gl/examples/layers + context.clear(context.COLOR_BUFFER_BIT); } - const bitmap = await createImageBitmap(canvas); - worker.postMessage( - { - id, - bitmap, - width: canvas.width, - height: canvas.height, - dataURLOptions: options.dataURLOptions, - }, - [bitmap], - ); - }); + } + + createImageBitmap(canvas) + .then((bitmap) => { + worker.postMessage( + { + id, + bitmap, + width: canvas.width, + height: canvas.height, + dataURLOptions: options.dataURLOptions, + }, + [bitmap], + ); + }) + .catch((error) => { + callbackWrapper(() => { + throw error; + })(); + }); + }); rafId = requestAnimationFrame(takeCanvasSnapshots); };