Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,35 +21,37 @@ if (!window.$RC) {
window.$RM = new Map();
}

if (document.readyState === 'loading') {
if (document.body != null) {
if (document.body != null) {
if (document.readyState === 'loading') {
installFizzInstrObserver(document.body);
} else {
// body may not exist yet if the fizz runtime is sent in <head>
// (e.g. as a preinit resource)
// $FlowFixMe[recursive-definition]
const domBodyObserver = new MutationObserver(() => {
// We expect the body node to be stable once parsed / created
if (document.body) {
if (document.readyState === 'loading') {
installFizzInstrObserver(document.body);
}
handleExistingNodes();
// We can call disconnect without takeRecord here,
// since we only expect a single document.body
domBodyObserver.disconnect();
}
});
// documentElement must already exist at this point
// $FlowFixMe[incompatible-call]
domBodyObserver.observe(document.documentElement, {childList: true});
}
}
// $FlowFixMe[incompatible-cast]
handleExistingNodes((document.body /*: HTMLElement */));
} else {
// Document must be loading -- body may not exist yet if the fizz external
// runtime is sent in <head> (e.g. as a preinit resource)
// $FlowFixMe[recursive-definition]
const domBodyObserver = new MutationObserver(() => {
// We expect the body node to be stable once parsed / created
if (document.body != null) {
if (document.readyState === 'loading') {
installFizzInstrObserver(document.body);
}
// $FlowFixMe[incompatible-cast]
handleExistingNodes((document.body /*: HTMLElement */));

handleExistingNodes();
// We can call disconnect without takeRecord here,
// since we only expect a single document.body
domBodyObserver.disconnect();
}
});
// documentElement must already exist at this point
// $FlowFixMe[incompatible-call]
domBodyObserver.observe(document.documentElement, {childList: true});
}

function handleExistingNodes() {
const existingNodes = document.getElementsByTagName('template');
function handleExistingNodes(target /*: HTMLElement */) {
const existingNodes = Array.from(target.children);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure querySelectorAll will outperform this by a lot. In practice it may not make a huge difference given the (un)popularity of template in many sites

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not by a lot but I did find a jsperf type benchmark that showed it was faster

Copy link
Contributor Author

@mofeiZ mofeiZ Mar 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick review + feedback here! I had assumed that querySelectorAll might be slower for a deep + widely branching tree, and that document.body.children was likely small. I'm not at all familiar with browser DOM perf, will go ahead and change this.

I ran some ad-hoc timing on my laptop (calling querySelectorAll and Array.from(.children) 1000x on DOMContentLoaded event for facebook home page, a 'representative DOM sample'), and it looks like querySelectorAll('template') is generally faster.

Safari:
Pasted image 20230304110032

Chrome:
image

for (let i = 0; i < existingNodes.length; i++) {
handleNode(existingNodes[i]);
}
Expand Down