Skip to content

Commit 2e80990

Browse files
committed
perf: improve frame locating performance
1 parent 41d2d6f commit 2e80990

1 file changed

Lines changed: 43 additions & 9 deletions

File tree

src/selection/message.ts

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,59 @@ interface PostMessageEvent extends MessageEvent {
88
}
99
}
1010

11+
type FrameElement = HTMLIFrameElement | HTMLFrameElement
12+
13+
const frameBySource = new WeakMap<object, FrameElement>()
14+
15+
function isFrameElement(element: Element | null): element is FrameElement {
16+
return (
17+
element instanceof HTMLIFrameElement || element instanceof HTMLFrameElement
18+
)
19+
}
20+
1121
function findFrameBySource(source: MessageEventSource | null) {
22+
if (!source) {
23+
return
24+
}
25+
26+
const cachedFrame = frameBySource.get(source)
27+
if (
28+
cachedFrame &&
29+
cachedFrame.isConnected &&
30+
cachedFrame.contentWindow === source
31+
) {
32+
return cachedFrame
33+
}
34+
35+
// This also works for frames inside closed shadow roots when same-origin.
36+
try {
37+
const frame = (source as Window).frameElement
38+
if (isFrameElement(frame)) {
39+
frameBySource.set(source, frame)
40+
return frame
41+
}
42+
} catch {
43+
// Accessing frameElement on a cross-origin WindowProxy throws.
44+
}
45+
1246
const roots: Array<Document | ShadowRoot> = [document]
1347

1448
while (roots.length) {
1549
const root = roots.pop()!
16-
const frame = Array.from(
17-
root.querySelectorAll<HTMLIFrameElement | HTMLFrameElement>(
18-
'iframe, frame'
19-
)
20-
).find(({ contentWindow }) => contentWindow === source)
50+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT)
51+
let element = walker.nextNode() as Element | null
2152

22-
if (frame) {
23-
return frame
24-
}
53+
while (element) {
54+
if (isFrameElement(element) && element.contentWindow === source) {
55+
frameBySource.set(source, element)
56+
return element
57+
}
2558

26-
for (const element of Array.from(root.querySelectorAll('*'))) {
2759
if (element.shadowRoot) {
2860
roots.push(element.shadowRoot)
2961
}
62+
63+
element = walker.nextNode() as Element | null
3064
}
3165
}
3266
}

0 commit comments

Comments
 (0)