Skip to content

Commit 8e81c95

Browse files
[scramjet/core] optimize createWrapFn by caching parent and top lookups (#120)
1 parent 9f5ea55 commit 8e81c95

File tree

1 file changed

+38
-36
lines changed
  • packages/core/src/client/shared

1 file changed

+38
-36
lines changed

packages/core/src/client/shared/wrap.ts

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,49 +5,51 @@ import { ScramjetClient } from "@client/index";
55
import { indirectEval } from "@client/shared/eval";
66

77
export function createWrapFn(client: ScramjetClient, self: typeof globalThis) {
8+
let wrappedParent: typeof globalThis | null = null;
9+
let wrappedTop: typeof globalThis | null = null;
10+
if (iswindow) {
11+
try {
12+
if (SCRAMJETCLIENT in self.parent) {
13+
// ... then we're in a subframe, and the parent frame is also in a proxy context, so we should return its proxy
14+
wrappedParent = self.parent;
15+
} else {
16+
// ... then we should pretend we aren't nested and return the current window
17+
wrappedParent = self;
18+
}
19+
} catch {
20+
// accessing self.parent can throw if it's cross-origin, in which case we should also pretend we aren't nested
21+
wrappedParent = self;
22+
}
23+
// instead of returning top, we need to return the uppermost parent that's inside a scramjet context
24+
let current = self;
25+
for (;;) {
26+
const test = current.parent.self;
27+
if (test === current) break; // there is no parent, actual or emulated.
28+
29+
try {
30+
// ... then `test` represents a window outside of the proxy context, and therefore `current` is the topmost window in the proxy context
31+
if (!(SCRAMJETCLIENT in test)) break;
32+
} catch {
33+
// accessing test can throw if it's cross-origin, in which case we should also break
34+
break;
35+
}
36+
// test is also insde a proxy, so we should continue up the chain
37+
current = test;
38+
}
39+
wrappedTop = current;
40+
}
41+
842
return function (identifier: any, strict: boolean) {
943
if (identifier === self.location) return client.locationProxy;
1044
if (identifier === self.eval) return indirectEval.bind(client, strict);
11-
12-
// TODO only do this once on init. a page can't suddenly gain a parent i don't think
1345
if (iswindow) {
1446
if (identifier === self.parent) {
15-
try {
16-
if (SCRAMJETCLIENT in self.parent) {
17-
// ... then we're in a subframe, and the parent frame is also in a proxy context, so we should return its proxy
18-
return self.parent;
19-
} else {
20-
// ... then we should pretend we aren't nested and return the current window
21-
return self;
22-
}
23-
} catch {
24-
// accessing self.parent can throw if it's cross-origin, in which case we should also pretend we aren't nested
25-
return self;
26-
}
27-
} else if (identifier === self.top) {
28-
// instead of returning top, we need to return the uppermost parent that's inside a scramjet context
29-
let current = self;
30-
31-
for (;;) {
32-
const test = current.parent.self;
33-
if (test === current) break; // there is no parent, actual or emulated.
34-
35-
try {
36-
// ... then `test` represents a window outside of the proxy context, and therefore `current` is the topmost window in the proxy context
37-
if (!(SCRAMJETCLIENT in test)) break;
38-
} catch {
39-
// accessing test can throw if it's cross-origin, in which case we should also break
40-
break;
41-
}
42-
43-
// test is also insde a proxy, so we should continue up the chain
44-
current = test;
45-
}
46-
47-
return current;
47+
return wrappedParent;
48+
}
49+
else if (identifier === self.top) {
50+
return wrappedTop;
4851
}
4952
}
50-
5153
return identifier;
5254
};
5355
}

0 commit comments

Comments
 (0)