From a5d77ea4f011e62020816e65ad2682eb25712972 Mon Sep 17 00:00:00 2001 From: Yanzhen Yu Date: Wed, 1 Apr 2026 12:00:00 +0800 Subject: [PATCH] add iframe load timeout --- src/snapshot.ts | 67 +++++++++++++++++++++++++++++-------------- typings/snapshot.d.ts | 2 ++ 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/src/snapshot.ts b/src/snapshot.ts index 9ddc39d5..77544656 100644 --- a/src/snapshot.ts +++ b/src/snapshot.ts @@ -200,14 +200,26 @@ export function _isBlockedElement( function onceIframeLoaded( iframeEl: HTMLIFrameElement, listener: () => unknown, + iframeLoadTimeout: number, ) { const win = iframeEl.contentWindow; if (!win) { return; } // document is loading + let fired = false; if (win.document.readyState !== 'complete') { - iframeEl.addEventListener('load', listener); + const timer = setTimeout(() => { + if (!fired) { + listener(); + fired = true; + } + }, iframeLoadTimeout); + iframeEl.addEventListener('load', () => { + clearTimeout(timer); + fired = true; + listener(); + }); return; } // check blank frame for Chrome @@ -519,6 +531,7 @@ export function serializeNodeWithId( preserveWhiteSpace?: boolean; onSerialize?: (n: INode) => unknown; onIframeLoad?: (iframeINode: INode, node: serializedNodeWithId) => unknown; + iframeLoadTimeout?: number; }, ): serializedNodeWithId | null { const { @@ -533,6 +546,7 @@ export function serializeNodeWithId( recordCanvas = false, onSerialize, onIframeLoad, + iframeLoadTimeout = 5000, } = options; let { preserveWhiteSpace = true } = options; const _serializedNode = serializeNode(n, { @@ -606,6 +620,7 @@ export function serializeNodeWithId( preserveWhiteSpace, onSerialize, onIframeLoad, + iframeLoadTimeout, }); if (serializedChildNode) { serializedNode.childNodes.push(serializedChildNode); @@ -617,29 +632,34 @@ export function serializeNodeWithId( serializedNode.type === NodeType.Element && serializedNode.tagName === 'iframe' ) { - onceIframeLoaded(n as HTMLIFrameElement, () => { - const iframeDoc = (n as HTMLIFrameElement).contentDocument; - if (iframeDoc && onIframeLoad) { - const serializedIframeNode = serializeNodeWithId(iframeDoc, { - doc: iframeDoc, - map, - blockClass, - blockSelector, - skipChild: false, - inlineStylesheet, - maskInputOptions, - slimDOMOptions, - recordCanvas, - preserveWhiteSpace, - onSerialize, - onIframeLoad, - }); + onceIframeLoaded( + n as HTMLIFrameElement, + () => { + const iframeDoc = (n as HTMLIFrameElement).contentDocument; + if (iframeDoc && onIframeLoad) { + const serializedIframeNode = serializeNodeWithId(iframeDoc, { + doc: iframeDoc, + map, + blockClass, + blockSelector, + skipChild: false, + inlineStylesheet, + maskInputOptions, + slimDOMOptions, + recordCanvas, + preserveWhiteSpace, + onSerialize, + onIframeLoad, + iframeLoadTimeout, + }); - if (serializedIframeNode) { - onIframeLoad(n as INode, serializedIframeNode); + if (serializedIframeNode) { + onIframeLoad(n as INode, serializedIframeNode); + } } - } - }); + }, + iframeLoadTimeout, + ); } return serializedNode; @@ -657,6 +677,7 @@ function snapshot( preserveWhiteSpace?: boolean; onSerialize?: (n: INode) => unknown; onIframeLoad?: (iframeINode: INode, node: serializedNodeWithId) => unknown; + iframeLoadTimeout?: number; }, ): [serializedNodeWithId | null, idNodeMap] { const { @@ -669,6 +690,7 @@ function snapshot( preserveWhiteSpace, onSerialize, onIframeLoad, + iframeLoadTimeout, } = options || {}; const idNodeMap: idNodeMap = {}; const maskInputOptions: MaskInputOptions = @@ -725,6 +747,7 @@ function snapshot( preserveWhiteSpace, onSerialize, onIframeLoad, + iframeLoadTimeout, }), idNodeMap, ]; diff --git a/typings/snapshot.d.ts b/typings/snapshot.d.ts index 053e3a19..296aaa83 100644 --- a/typings/snapshot.d.ts +++ b/typings/snapshot.d.ts @@ -17,6 +17,7 @@ export declare function serializeNodeWithId(n: Node | INode, options: { preserveWhiteSpace?: boolean; onSerialize?: (n: INode) => unknown; onIframeLoad?: (iframeINode: INode, node: serializedNodeWithId) => unknown; + iframeLoadTimeout?: number; }): serializedNodeWithId | null; declare function snapshot(n: Document, options?: { blockClass?: string | RegExp; @@ -28,6 +29,7 @@ declare function snapshot(n: Document, options?: { preserveWhiteSpace?: boolean; onSerialize?: (n: INode) => unknown; onIframeLoad?: (iframeINode: INode, node: serializedNodeWithId) => unknown; + iframeLoadTimeout?: number; }): [serializedNodeWithId | null, idNodeMap]; export declare function visitSnapshot(node: serializedNodeWithId, onVisit: (node: serializedNodeWithId) => unknown): void; export declare function cleanupSnapshot(): void;