-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.js
More file actions
183 lines (155 loc) · 8.23 KB
/
Copy pathmain.js
File metadata and controls
183 lines (155 loc) · 8.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
'use strict';
const ITEM_COUNT = 3000;
const MATRIX_QUOTES = [
"What is real? How do you define real?",
"There is no spoon.",
"I know kung fu.",
"Show me.",
"Free your mind.",
"The Matrix has you.",
"Follow the white rabbit.",
"Unfortunately, no one can be told what the Matrix is. You have to see it for yourself.",
"You take the red pill — you stay in Wonderland, and I show you how deep the rabbit hole goes.",
"You take the blue pill — the story ends, you wake up in your bed and believe whatever you want to believe.",
"I'm trying to free your mind, Neo. But I can only show you the door. You're the one that has to walk through it.",
"Do not try and bend the spoon. That's impossible. Instead, only try to realize the truth.",
"What truth? There is no spoon.",
"Then you'll see that it is not the spoon that bends, it is only yourself.",
"Have you ever had a dream, Neo, that you were so sure was real?",
"What if you were unable to wake from that dream? How would you know the difference between the dream world and the real world?",
"The Matrix is everywhere. It is all around us.",
"You can feel it when you go to work, when you go to church, when you pay your taxes.",
"It is the world that has been pulled over your eyes to blind you from the truth.",
"That you are a slave, Neo. Like everyone else, you were born into bondage.",
"I didn't say it would be easy, Neo. I just said it would be the truth.",
"Dodge this.",
"My name is Neo.",
"Guns. Lots of guns.",
"No. I don't believe it.",
"I'm not afraid anymore.",
"Never send a human to do a machine's job.",
"You hear that, Mr. Anderson? That is the sound of inevitability.",
"Mr. Anderson. Welcome back. We missed you.",
"You must be able to see it, Mr. Anderson. You must know it by now.",
"I can see it in your eyes. You have the look of a man who accepts what he sees because he is expecting to wake up.",
"Ironically, this is not far from the truth.",
"Do you believe in fate, Neo?",
"No. Because I don't like the idea that I'm not in control of my life.",
"I know you're out there. I can feel you now.",
"I know that you're afraid. You're afraid of us. You're afraid of change.",
"I don't know the future. I didn't come here to tell you how this is going to end.",
"I came here to tell you how it's going to begin.",
"I'm going to hang up this phone, and then I'm going to show these people what you don't want them to see.",
"I'm going to show them a world without you.",
"A world without rules and controls, without borders or boundaries.",
"A world where anything is possible.",
"Where we go from there is a choice I leave to you.",
"The body cannot live without the mind.",
"Throughout human history, we have been dependent on machines to survive.",
"Fate, it seems, is not without a sense of irony.",
"This is your last chance. After this, there is no turning back.",
"Remember, all I'm offering is the truth. Nothing more.",
"Welcome to the real world.",
"We never free a mind once it's reached a certain age.",
"The mind has trouble letting go.",
"You have to understand, most of these people are not ready to be unplugged.",
"And many of them are so inured, so hopelessly dependent on the system, that they will fight to protect it.",
"Were you listening to me, Neo? Or were you looking at the woman in the red dress?",
"Sentient programs come and go, but I am a constant.",
"Everything that has a beginning has an end.",
"I can feel you now. You are afraid.",
"Why, Mr. Anderson? Why do you do it?",
"Why get up? Why keep fighting?",
"Do you believe you're fighting for something? For more than your survival?",
"Can you tell me what it is? Do you even know?",
"Is it freedom? Or truth? Perhaps peace?",
"Could it be for love?",
"Illusions, Mr. Anderson. Vagaries of perception.",
"The temporary constructs of a feeble human intellect.",
"The inevitable result of the imperfect I create.",
"Accidents. The nature of rubber, treading on the road.",
"Choice is an illusion created between those with power and those without.",
"The key is to be the one making the choice.",
"The Oracle told me I would find you.",
"She told me to say: 'Everything that has a beginning has an end, Neo.'",
];
const container = document.getElementById('scroll-container');
const list = document.getElementById('item-list');
const btnReproduce = document.getElementById('btn-reproduce');
const btnFix = document.getElementById('btn-fix');
const btnReset = document.getElementById('btn-reset');
// ── Heavy DOM tree generation ─────────────────────────────────────────────────
function buildDOMTree() {
const fragment = document.createDocumentFragment();
for (let i = 0; i < ITEM_COUNT; i++) {
const item = document.createElement('div');
item.className = 'item';
item.textContent = MATRIX_QUOTES[i % MATRIX_QUOTES.length];
const inner = document.createElement('div');
inner.className = 'item-inner';
const detail = document.createElement('span');
detail.className = 'item-detail';
detail.textContent = `id: ${i + 1}`;
inner.appendChild(detail);
item.appendChild(inner);
fragment.appendChild(item);
}
list.appendChild(fragment);
}
// ── Scroll to bottom so the reset is visible ─────────────────────────────────
function scrollToBottom() {
container.scrollTop = container.scrollHeight;
}
// ── Problematic version: Forced Synchronous Layout ───────────────────────────
//
// Sequence that triggers the FSL:
// 1. classList.toggle → invalidates styles (marks the tree as dirty)
// 2. scrollTop = 0 → the browser needs up-to-date geometry to apply
// the scroll, forcing an immediate synchronous layout
// (long RunTask visible in the Performance Panel).
function reproduceIssue() {
scrollToBottom();
// Small delay so the scroll paints before measuring
setTimeout(() => {
console.time('reproduce: forced synchronous layout');
// Step 1 — invalidate styles in bulk
container.classList.toggle('state-a');
container.classList.toggle('state-b');
// Step 2 — geometric property access after invalidation → FSL
container.scrollTop = 0;
console.timeEnd('reproduce: forced synchronous layout');
}, 100);
}
// ── Fixed version: defer scroll with double rAF ───────────────────────────────
//
// rAF fires BEFORE the browser runs Recalculate Style + Layout for that frame,
// so a single rAF is not enough — styles are still dirty when it fires.
//
// Double rAF breaks the cycle:
// 1st rAF: styles are dirty, but we don't touch geometry here.
// The browser then processes Recalculate Style + Layout naturally.
// 2nd rAF: fires in the next frame when the style tree is clean.
// Setting scrollTop now no longer forces a layout.
function fixIssue() {
scrollToBottom();
setTimeout(() => {
console.time('fix: deferred scroll with double rAF');
// Step 1 — invalidate styles (same as before)
container.classList.toggle('state-a');
container.classList.toggle('state-b');
// Step 2 — first rAF: let the browser process Recalculate Style + Layout
requestAnimationFrame(() => {
// Step 3 — second rAF: style tree is clean, no FSL
requestAnimationFrame(() => {
container.scrollTop = 0;
console.timeEnd('fix: deferred scroll with double rAF');
});
});
}, 100);
}
// ── Event listeners ───────────────────────────────────────────────────────────
btnReproduce.addEventListener('click', reproduceIssue);
btnFix.addEventListener('click', fixIssue);
btnReset.addEventListener('click', scrollToBottom);
// ── Init ──────────────────────────────────────────────────────────────────────
buildDOMTree();