-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
1068 lines (907 loc) · 57.9 KB
/
index.html
File metadata and controls
1068 lines (907 loc) · 57.9 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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Pageload examples</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Learn how a web page loads by example">
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
<link rel="stylesheet" href="./assets/new.css">
<link rel="preload" as="style" href="./assets/inter.css" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="./assets/inter.css"></noscript>
<script defer src="./assets/microlight.js"></script>
</head>
<body>
<header>
<h1>🌍 Page loading</h1>
</header>
<details id="toc" open>
<summary>Table of contents</summary>
<ul>
<li><a href="#basic-html">Loading a web site is a gradual process</a></li>
<li><a href="#basic-html-style">External styles block rendering, but not document parsing</a></li>
<li><a href="#basic-html-style-inline">Fast styled rendering, with inline styles</a></li>
<li><a href="#basic-html-style-critical">Sweet spot: inline critical styles</a></li>
<li><a href="#basic-html-script">Scripts block document parsing, but not rendering</a></li>
<li><a href="#basic-html-style-script">Scripts execution requires to finish any ongoing styles loading</a></li>
<li><a href="#basic-html-style-script-defer">Deferred scripts don't block document parsing</a></li>
<li><a href="#basic-html-style-script-async">Async scripts block (almost) nothing</a></li>
<li><a href="#basic-html-script-dynamic">Dynamic scripts behave like async by default</a></li>
<li><a href="#basic-html-style-script-inline-async">Execute inline scripts without waiting for styles</a></li>
<li><a href="#basic-html-load">The "load" event fires once all resources in turn have fired "load"</a></li>
</ul>
</details>
<hr>
<article id="basic-html">
<h2>📝 Loading a web site is a gradual process</h2>
<figure>
<blockquote>
It's important to understand that [...] is a gradual process. For better user experience, the rendering engine will try to display contents on the screen as soon as possible. It will not wait until all HTML is parsed before starting to build and layout the render tree. Parts of the content will be parsed and displayed, while the process continues with the rest of the contents that keeps coming from the network.
</blockquote>
<figcaption>
— Tali Garsiel, <cite>How browsers work</cite>
</figcaption>
</figure>
<p>Let's demonstrate that fact by loading a page with lots of text content. Page download is throttled by the server and takes a long time.</p>
<p>Try to scroll down while the page is being downloaded.</p>
<p>The display keeps updating, but <code>DOMContentLoaded</code> event won't trigger until the download and parsing of the HTML is <em>completed</em>.</p>
<p>
<a href="https://proxy-throttle.comu.deno.net/?factor=5&url=https%3A%2F%2Fesroyo.github.io%2Fpageload-examples%2Fexamples%2Fbasic-html%2F" target="_blank"><button>Open example</button></a>
☑
<a href="https://www.webpagetest.org/result/230911_BiDc74_APB/3/details/" target="_blank">Webpage test result</a>
</p>
<details>
<summary>HTML outline</summary>
<pre><code><html throttle="5">
<head>
</head>
<body>
<!-- Long HTML contents -->
</body>
</html></code></pre>
</details>
<details>
<summary>Timeline</summary>
<figure>
<pre>
0.00 <span style="opacity:.5">┬</span> startTime
18.10 <span style="opacity:.5">├</span> requestStart
171.60 <span style="opacity:.5">├</span> responseStart
<span style="opacity:.5">┊</span>
2925.30 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-paint</span>
2925.30 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-contentful-paint</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
30235.70 <span style="opacity:.5">├</span> responseEnd
30236.70 <span style="opacity:.5">├</span> domInteractive
30236.80 <span style="opacity:.5">├</span> domContentLoadedEventStart
30236.80 <span style="opacity:.5">├</span> domContentLoadedEventEnd
30237.10 <span style="opacity:.5">├</span> domComplete
30237.20 <span style="opacity:.5">├</span> loadEventStart
30237.20 <span style="opacity:.5">└</span> loadEventEnd</pre>
<figcaption>
Timeline: It shows the first paint happening much earlier than the HTML's response end.
</figcaption>
</figure>
</details>
<p>[<a href="#toc">TOP</a>]</p>
</article>
<hr>
<article id="basic-html-style">
<h2>📝 External styles block rendering, but not document parsing</h2>
<p>As we have seen in the previous example, the DOM content tree is gradually builded as the HTML is downloaded. What if we have an stylesheet link on that page?</p>
<p>An external stylesheet by itself does not block <em>all</em> of the process. The fetching of the stylesheet starts, but the HTML parsing continues. The <code>DOMContentLoaded</code> event will trigger regardless the style state.</p>
<p><em>However</em>, although the <code>DOMContentLoaded</code> event fires, <strong>the page won't be displayed to the user</strong> until the fetching of the style is done.</p>
<p>This means an stylesheet resource doesn't block the document parsing, but will block the rendering. From JavaScript land It feels strange to have no visual feedback when <code>DOMContentLoaded</code> has already fired. There seems to be no way to force the browser into the first paint.</p>
<p>If an style is added dynamically from JavaScript, It won't block the rendering. Even if that is done <em>before</em> the first render.</p>
<p>While there are pending styles to download and parse, the window `load` will not fire. No matter how late they have been added to the DOM.</p>
<p>Syles imported with <code>@import</code> statements from the external styles are considered part of the same loading process.</p>
<p>
<a href="https://esroyo.github.io/pageload-examples/examples/basic-html-style/" target="_blank"><button>Open example</button></a>
☑
<a href="https://www.webpagetest.org/result/230911_AiDcQN_AQV/1/details/" target="_blank">Webpage test result</a>
</p>
<details>
<summary>HTML outline</summary>
<pre><code><head>
<link rel="stylesheet" href="./assets/new.css" throttle="10">
</head>
<body>
<!-- Long HTML contents -->
</body></code></pre>
</details>
<details>
<summary>Timeline</summary>
<figure>
<pre>
0.00 <span style="opacity:.5">┬</span> startTime
27.90 <span style="opacity:.5">├</span> requestStart
174.90 <span style="opacity:.5">├</span> responseStart
177.90 <span style="opacity:.5">├</span> responseEnd
184.30 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">link("…mples/assets/new.css")</span>
194.10 <span style="opacity:.5">├</span> domInteractive
194.10 <span style="opacity:.5">├</span> domContentLoadedEventStart
194.20 <span style="opacity:.5">├</span> domContentLoadedEventEnd
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
10472.40 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">link("…mples/assets/new.css")</span>
10525.70 <span style="opacity:.5">├</span> domComplete
10525.80 <span style="opacity:.5">├</span> loadEventStart
10525.90 <span style="opacity:.5">├</span> loadEventEnd
10600.20 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-paint</span>
10600.20 <span style="opacity:.5">└</span> paint: <span style="opacity:.6">first-contentful-paint</span></pre>
<figcaption>
Timeline: It shows that an external style link does not block the document parsing nor the <code>DOMContentLoaded</code> event. However the first paint won't happen until the download and processing of the style resource ends.
</figcaption>
</figure>
</details>
<details>
<summary>Quirks</summary>
<ul>
<li><mark>Blink</mark>; When the <code>link</code> tag is located in the <code>head</code>, then as claimed the document parsing is not blocked. However if the <code>link</code> tag is located in the <code>body</code>, <strong>It blocks the document parsing</strong> (the hard way). Test it in <a href="https://esroyo.github.io/pageload-examples/examples/basic-html-style-body/" target="_blank">this secondary example</a>. Gecko and WebKit based browsers don't observe this difference between <code>body</code> and <code>head</code>.</li>
</ul>
</details>
<p>[<a href="#toc">TOP</a>]</p>
</article>
<hr>
<article id="basic-html-style-inline">
<h2>📝 Fast styled rendering, with inline styles</h2>
<p>We can achieve the gradual rendering effect seen on the <a href="#basic-html">first example</a> while displaying already styled content. It is possible by inlining the contents of the stylesheet.</p>
<p>Although inlining styles is a limited option (prevents caching, is difficult to scale),
for the shake of the example It is cool to see how the browser can build the DOM and render styled contents as the HTML is dowloaded.</p>
<p>
<a href="https://proxy-throttle.comu.deno.net/?factor=5&url=https%3A%2F%2Fesroyo.github.io%2Fpageload-examples%2Fexamples%2Fbasic-html-style-inline%2F" target="_blank"><button>Open example</button></a>
☑
<a href="https://www.webpagetest.org/result/230911_AiDcPN_AVE/2/details/" target="_blank">Webpage test result</a>
</p>
<details>
<summary>HTML outline</summary>
<pre><code><head>
<style>
/* Inlined CSS */
</style>
</head>
<body>
<!-- Long HTML contents -->
</body></code></pre>
</details>
<details>
<summary>Timeline</summary>
<figure>
<pre>
0.00 <span style="opacity:.5">┬</span> startTime
19.60 <span style="opacity:.5">├</span> requestStart
539.10 <span style="opacity:.5">├</span> responseStart
<span style="opacity:.5">┊</span>
3240.20 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-paint</span>
3240.20 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-contentful-paint</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
35312.40 <span style="opacity:.5">├</span> responseEnd
35313.20 <span style="opacity:.5">├</span> domInteractive
35313.20 <span style="opacity:.5">├</span> domContentLoadedEventStart
35313.20 <span style="opacity:.5">├</span> domContentLoadedEventEnd
35313.40 <span style="opacity:.5">├</span> domComplete
35313.40 <span style="opacity:.5">├</span> loadEventStart
35313.40 <span style="opacity:.5">└</span> loadEventEnd</pre>
<figcaption>
Timeline: It shows an early painting, given there are no external resources.
</figcaption>
</figure>
</details>
<p>[<a href="#toc">TOP</a>]</p>
</article>
<hr>
<article id="basic-html-style-critical">
<h2>📝 Sweet spot: inline critical styles</h2>
<p>The best experience comes when only <a href="https://css-tricks.com/authoring-critical-fold-css/" target="_blank">critical styles</a> are inlined, as we get the gradual rendering effect of styled content.</p>
<p>However It forces the loading of the non-critical styles on a deferred stage. The <code>media</code> attribute <a href="https://github.com/filamentgroup/loadCSS" target="_blank">trick</a> is a well known option for the deferred load. Although It feels hackish and relies on JavaScript.</p>
<p>Another possiblity would be to put the non-critical styles in a <code>link rel="preload"</code> tag. That <code>link</code> wouldn't block document parsing nor rendering. Finally place the regular <code>link</code> to the same style at the very end of the <code>body</code>. Rendering can't be blocked if something has been already painted.</p>
<p>This would be a sweet spot solution, except for the quirk commented on the <a href="#basic-html-style">external styles example</a>. Blink blocks the document parsing when it finds a style <code>link</code> in the <code>body</code>. Thus although the visual exeperience is good, the delay of <code>DOMContentLoaded</code> makes this solution non-generalizable.</p>
<p><a href="https://proxy-throttle.comu.deno.net/?factor=2&url=https%3A%2F%2Fesroyo.github.io%2Fpageload-examples%2Fexamples%2Fbasic-html-style-critical-blink%2F" target="_blank">This secondary example</a> shows the alternative for Blink (using the <code>onload</code> attribute).</p>
<p>On a more general note, be aware of abusing preloading. On HTTP/1.1 you can easily hit the number of concurrent connections to the same domain (6 in Chrome). Aside from that, remember that you are hand-picking high priority resources. That implicitly de-prioritizes other resources.</p>
<p>
<a href="https://proxy-throttle.comu.deno.net/?factor=2&url=https%3A%2F%2Fesroyo.github.io%2Fpageload-examples%2Fexamples%2Fbasic-html-style-critical%2F" target="_blank"><button>Open example</button></a>
☑
<a href="https://www.webpagetest.org/result/230911_AiDc4T_ATZ/3/details/" target="_blank">Webpage test result</a>
</p>
<details>
<summary>HTML outline</summary>
<pre><code><head>
<link rel="preload" as="style" href="./assets/new.css" throttle="15">
<style>
/* Limited critical CSS */
</style>
</head>
<body>
<!-- Long HTML contents -->
<link rel="stylesheet" href="./assets/new.css" throttle="15">
</body></code></pre>
</details>
<details>
<summary>Timeline</summary>
<figure>
<pre>
0.00 <span style="opacity:.5">┬</span> startTime
83.00 <span style="opacity:.5">├</span> requestStart
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
8135.00 <span style="opacity:.5">├</span> responseStart
8199.00 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">link("…mples/assets/new.css")</span>
8224.00 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-contentful-paint</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
17041.00 <span style="opacity:.5">├</span> responseEnd
17056.00 <span style="opacity:.5">├</span> domInteractive
17056.00 <span style="opacity:.5">├</span> domContentLoadedEventStart
17056.00 <span style="opacity:.5">├</span> domContentLoadedEventEnd
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
23495.00 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">link("…mples/assets/new.css")</span>
23667.00 <span style="opacity:.5">├</span> domComplete
23667.00 <span style="opacity:.5">├</span> loadEventStart
23667.00 <span style="opacity:.5">└</span> loadEventEnd</pre>
<figcaption>
Timeline: It shows an early paint. Contents are displayed as they arrive, styled with the critical inlined styles. Meanwhile non-critical styles are being preloaded and won't block anything. Once the non-critical styles are downloaded the styles are applied (reflow). This sequence of events is taken from a WebKit based browser.
</figcaption>
</figure>
</details>
<p>[<a href="#toc">TOP</a>]</p>
</article>
<hr>
<article id="basic-html-script">
<h2>📝 Scripts block document parsing, but not rendering</h2>
<p>When an script is found in the HTML, the browser pauses the document parsing until the script is executed.</p>
<p>If the script is external, It must be fetched and then executed. Document parsing won't continue until the script ends execution.</p>
<p>Givent that an script does not necessarily block the rendering, the location of the script in the document is important. If the script is located at the end of the body, some rendering is possible</p>.
<p>
<a href="https://esroyo.github.io/pageload-examples/examples/basic-html-script/" target="_blank"><button>Open example</button></a>
☑
<a href="https://www.webpagetest.org/result/230911_BiDcEF_AX4/3/details/" target="_blank">Webpage test result</a>
</p>
<details>
<summary>HTML outline</summary>
<pre><code><head>
</head>
<body>
<!-- Long HTML contents -->
<script src="./assets/junk.js" throttle="10"></script>
</body></code></pre>
</details>
<details>
<summary>Timeline</summary>
<figure>
<pre>
0.00 <span style="opacity:.5">┬</span> startTime
25.20 <span style="opacity:.5">├</span> requestStart
174.00 <span style="opacity:.5">├</span> responseStart
177.90 <span style="opacity:.5">├</span> responseEnd
184.80 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">script("…mples/assets/junk.js")</span>
247.70 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-paint</span>
247.70 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-contentful-paint</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
10471.40 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">script("…mples/assets/junk.js")</span>
10473.40 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution</span>
10478.60 <span style="opacity:.5">├</span> domInteractive
10478.70 <span style="opacity:.5">├</span> domContentLoadedEventStart
10478.70 <span style="opacity:.5">├</span> domContentLoadedEventEnd
10641.20 <span style="opacity:.5">├</span> domComplete
10641.30 <span style="opacity:.5">├</span> loadEventStart
10641.30 <span style="opacity:.5">└</span> loadEventEnd</pre>
<figcaption>
Timeline: It shows that an external script blocks document parsing. Interactive state won't be reached until the script is fetched and executed. However if enough document content has been already parsed, paint still happens.
</figcaption>
</figure>
</details>
<p>[<a href="#toc">TOP</a>]</p>
</article>
<hr>
<article id="basic-html-style-script">
<h2>📝 Scripts execution requires to finish the ongoing styles loading</h2>
<p>As we have seen <a href="#basic-html-style">previously</a>, and external stylesheet will not block the document parsing. However if the external style is followed by an script, things change.</p>
<p>An script not only pauses the document parsing, but also requires to finish the <em>ongoing</em> styles loading. Only then will start its execution.</p>
<p>So document parsing becomes blocked when it gets to an script. In turn the script execution is blocked by the loading styles.</p>
<p>Note we emphasize the fact that only <em>ongoing</em> loading styles will block the script. If the order is inverted and the script is placed before the style, It will get executed immediately. See that in <a href="https://esroyo.github.io/pageload-examples/examples/basic-html-script-style/" target="_blank">this secondary example</a> (timeline will be similar to the <a href="#basic-html-style">second case</a>).</p>
<p><strong>This rule only applies to <em>initial</em> styles</strong>. That is to stylesheet links that are in the initial HTML response. Stylesheet links added dynamically do not block successive scripts, even if they are added to the document before those scripts.</p>
<p>When the initial stylesheets contain <code>@import</code> statements, those are considered part of the same style loading. Thus importing styles from styles is a serious concern, as it pospones script execution and rendering. Check that in <a href="https://esroyo.github.io/pageload-examples/examples/basic-html-style-style-script/" target="_blank">this other secondary example</a>.</p>
<p>
<a href="https://esroyo.github.io/pageload-examples/examples/basic-html-style-script/" target="_blank"><button>Open example</button></a>
☑
<a href="https://www.webpagetest.org/result/230911_AiDc2R_AWX/2/details/" target="_blank">Webpage test result</a>
</p>
<details>
<summary>HTML outline</summary>
<pre><code><head>
<link rel="stylesheet" href="./assets/new.css" throttle="10">
</head>
<body>
<!-- Long HTML contents -->
<script>
performance.mark('script execution');
</script>
</body></code></pre>
</details>
<details>
<summary>Timeline</summary>
<figure>
<pre>
0.00 <span style="opacity:.5">┬</span> startTime
20.00 <span style="opacity:.5">├</span> requestStart
170.80 <span style="opacity:.5">├</span> responseStart
177.70 <span style="opacity:.5">├</span> responseEnd
184.30 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">link("…mples/assets/new.css")</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
10398.10 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">link("…mples/assets/new.css")</span>
10523.80 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution</span>
10581.60 <span style="opacity:.5">├</span> domInteractive
10581.60 <span style="opacity:.5">├</span> domContentLoadedEventStart
10581.60 <span style="opacity:.5">├</span> domContentLoadedEventEnd
10604.80 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-paint</span>
10604.80 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-contentful-paint</span>
10721.30 <span style="opacity:.5">├</span> domComplete
10721.50 <span style="opacity:.5">├</span> loadEventStart
10721.50 <span style="opacity:.5">└</span> loadEventEnd</pre>
<figcaption>
Timeline: The external style by itself would not block the document parsing, as seen <a href="#basic-html-style">previously</a>. However the script gets blocked by the style loading, and in turn the script blocks the document parsing. Thus DOM interactive is bounded by the style loading plus the script execution.
</figcaption>
</figure>
</details>
<p>[<a href="#toc">TOP</a>]</p>
</article>
<hr>
<article id="basic-html-style-script-defer">
<h2>📝 Deferred scripts don't block document parsing</h2>
<p>Even though deferred scripts don't block document parsing and get downloaded in parallel (with low priority), they share some key behaviours with the "normal" synchronous script tags:
<ul>
<li>They are executed in the order they were added to the DOM tree.</li>
<li>They are executed before <code>DOMContentLoaded</code> event.</li>
<li>They don't block rendering. (see <a href="https://esroyo.github.io/pageload-examples/examples/basic-html-script-defer/" target="_blank">secondary example</a>)</li>
<li>Before execution they must wait for ongoing styles loading (if any) to end.</li>
</ul>
</p>
<p>They are all executed at the same time, before <code>DOMContentLoaded</code>. Therefore all deferred scripts need to be completely downloaded before any of them can execute.</p>
<p>Roughtly we can think of deferred scripts as synchronous scripts whose execution is pushed towards the end of the document parsing process, with the benefit of prefetching them.</p>
<p>As a side note, scripts of <code>type=module</code> behave like deferred scripts. They keep order, execute once the document is interative, wait for styles, etc. The most notable difference is that they probably get higher download priority. Also they won't have access to <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/currentScript" target="_blank">document.currentScript</a>.</p>
<p><a href="https://esroyo.github.io/pageload-examples/examples/basic-html-style-script-defer/" target="_blank"><button>Open example</button></a>
☑
<a href="https://www.webpagetest.org/result/230911_BiDcWN_AZP/1/details/" target="_blank">Webpage test result</a>
</p>
<details>
<summary>HTML outline</summary>
<pre><code><head>
<link rel="stylesheet" href="./assets/new.css" throttle="10">
</head>
<body>
<script src="./assets/junk.js?def1" defer throttle="5"></script>
<script src="./assets/junk.js?def2" defer throttle="2"></script>
<!-- Long HTML contents -->
</body></code></pre>
</details>
<details>
<summary>Timeline</summary>
<figure>
<pre>
0.00 <span style="opacity:.5">┬</span> startTime
19.90 <span style="opacity:.5">├</span> requestStart
168.20 <span style="opacity:.5">├</span> responseStart
174.00 <span style="opacity:.5">├</span> responseEnd
178.40 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">link("…mples/assets/new.css")</span>
178.60 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">script("…/assets/junk.js?def1")</span>
178.90 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">script("…/assets/junk.js?def2")</span>
183.70 <span style="opacity:.5">├</span> domInteractive
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
2385.70 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">script("…/assets/junk.js?def2")</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
5457.80 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">script("…/assets/junk.js?def1")</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
10372.80 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">link("…mples/assets/new.css")</span>
10420.90 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- deferred 1</span>
10421.20 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- deferred 2</span>
10421.20 <span style="opacity:.5">├</span> domContentLoadedEventStart
10421.20 <span style="opacity:.5">├</span> domContentLoadedEventEnd
10500.00 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-paint</span>
10500.00 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-contentful-paint</span>
10514.20 <span style="opacity:.5">├</span> domComplete
10514.20 <span style="opacity:.5">├</span> loadEventStart
10514.20 <span style="opacity:.5">└</span> loadEventEnd</pre>
<figcaption>
Timeline: It shows two deferred scripts that start to download as the document parses. The document parsing ends and It reaches the <em>interactive</em> state. The first deferred script takes 5s to download and the second takes 2s. They need to wait for the style download to end. Then both get executed in order. Finally <code>DOMContentLoaded</code> is fired. The rendering is hold by the style download, not the scripts. Without the external style, rendering would take place almost immediately.
</figcaption>
</figure>
</details>
<p>[<a href="#toc">TOP</a>]</p>
</article>
<hr>
<article id="basic-html-style-script-async">
<h2>📝 Async scripts block (almost) nothing</h2>
<p>Async scripts are like "free agents". They:
<ul>
<li>Do not block document parsing.</li>
<li>Do not block rendering.</li>
<li>Do not require the ongoing styles loading to end.</li>
<li>Do not require pending scripts to execute.</li>
<li>Will execute as soon as possible, once they are downloaded.</li>
<li>Because of that, they may delay ongoing critical processes! (for instance, they could execute while document parsing has not finished).</li>
<li>Finally, they do block the window <code>load</code> event.</li>
</ul>
</p>
<p><a href="https://proxy-throttle.comu.deno.net/?factor=0.2&url=https%3A%2F%2Fesroyo.github.io%2Fpageload-examples%2Fexamples%2Fbasic-html-style-script-async%2F" target="_blank"><button>Open example</button></a>
☑
<a href="https://www.webpagetest.org/result/230911_AiDcMS_AZF/1/details/" target="_blank">Webpage test result</a>
</p>
<details>
<summary>HTML outline</summary>
<pre><code><head>
<link rel="stylesheet" href="./assets/new.css" throttle="1">
</head>
<body>
<script async src="./assets/junk.js#async1" throttle="5"></script>
<script async src="./assets/fib.js#async2" throttle="0" data-fibonacci-number="42"></script>
<script async src="./assets/junk.js#async3" throttle="1"></script>
<!-- Long HTML contents -->
</body></code></pre>
</details>
<details>
<summary>Timeline</summary>
<figure>
<pre>
0.00 <span style="opacity:.5">┬</span> startTime
14.10 <span style="opacity:.5">├</span> requestStart
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
612.50 <span style="opacity:.5">├</span> responseStart
623.90 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">link("…mples/assets/new.css")</span>
624.80 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">script("…ssets/junk.js?async1")</span>
625.20 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">script("…assets/fib.js?async2")</span>
625.40 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">script("…ssets/junk.js?async3")</span>
<span style="opacity:.5">┊</span>
811.90 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">script("…assets/fib.js?async2")</span>
814.30 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- async 2</span>
814.30 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">start fib(42)</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
1399.80 <span style="opacity:.5">├</span> responseEnd
<span style="opacity:.5">┊</span>
1680.70 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">script("…ssets/junk.js?async3")</span>
1682.20 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">link("…mples/assets/new.css")</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
2955.60 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">end fib(42)</span>
2959.30 <span style="opacity:.5">├</span> domInteractive
2959.30 <span style="opacity:.5">├</span> domContentLoadedEventStart
2959.30 <span style="opacity:.5">├</span> domContentLoadedEventEnd
2967.30 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- async 3</span>
<span style="opacity:.5">┊</span>
3139.90 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-paint</span>
3139.90 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-contentful-paint</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
5835.90 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">script("…ssets/junk.js?async1")</span>
5837.10 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- async 1</span>
5837.20 <span style="opacity:.5">├</span> domComplete
5837.30 <span style="opacity:.5">├</span> loadEventStart
5837.30 <span style="opacity:.5">└</span> loadEventEnd</pre>
<figcaption>
Timeline: It shows that four external resources start loading (one style, three async scripts) while the document is being received and parsed. The 2nd async script is the first to end its download. At this point none of the other external resources, nor the document itself have been completely received yet. Execution of this 2nd async script starts and takes a while — around 2seconds, a very looong task! While this script is executing, three other resources have finished arriving (the style, the document itself, and the 3rd async script). They can't be processed while the 2nd script is executing. When the execution of the 2nd script ends, we are unblocked to continue processing stuff. The style is processed. The rest of the document is parsed and reaches the interactive state. And the 3rd async script gets executed. Finally some rendering happens. Much later, the 1st async script ends its download and executes. Only then the <code>load</code> event fires.
</figcaption>
</figure>
</details>
<p>[<a href="#toc">TOP</a>]</p>
</article>
<hr>
<article id="basic-html-script-dynamic">
<h2>📝 Dynamic scripts behave like async by default</h2>
<p>We consider dynamic scripts those that are created —and added to the DOM— using JavaScript. This can be done at any time, there is no restriction.</p>
<p>There are two types of dynamic scripts: async (the default), or sync. There is no straight way to create a dynamic script that acts as <code>defer</code>.</p>
<p>The insertion of a dynamic script does not block document parsing. Even if they are created in sync mode and are added before the document is <em>interactive</em> state.</p>
<p>Dynamic sync scripts block each other. They execute in the order they were added to document (the insertion position is irrelevant).</p>
<p>Dynamic async scripts behave exactly as non-dynamic async scripts: they almost block nothing, and get executed as soon as they are ready.</p>
<p>In fact any dynamic script may execute in the middle of critical processes like document parsing. It is important to keep your eyes open.</p>
<p>Finally, they do block the window <code>load</code> event. This is true for <em>every</em> dynamic script (async or sync), disregarding when they are added to the document. If they are added before <code>load</code> has fired, the event will be holded until the pending scripts execute.<p>
<p><a href="https://proxy-throttle.comu.deno.net/?factor=0.4&url=https%3A%2F%2Fesroyo.github.io%2Fpageload-examples%2Fexamples%2Fbasic-html-script-dynamic%2F" target="_blank"><button>Open example</button></a></p>
☑
<a href="https://www.webpagetest.org/result/230911_AiDc7V_B01/2/details/" target="_blank">Webpage test result</a>
</p>
<details>
<summary>HTML outline</summary>
<pre><code><head>
<script async src="./assets/junk.js?async1" throttle="0"></script>
</head>
<body>
<script async src="./assets/junk.js?async2" throttle="9"></script>
<script>
// mark: script execution -- inline 1
// Adds a dynamic async script "?dyn-async1" throttle=5
</script>
<script>
// mark: script execution -- inline 2
// Adds a dynamic async script "?dyn-async2" throttle=11
//
// After "?dyn-async2" execution, domComplete would arrive
// We will add a extra dynamic async script "?dyn-async3" to
// demostrate that domComplete is holded by this last extra script
</script>
<script defer src="./assets/junk.js?def1" throttle="6"></script>
<script>
// mark: script execution -- inline 3
// Adds a dynamic sync script "?dyn-sync1" throttle=7
</script>
<script defer src="./assets/junk.js?def2" throttle="4"></script>
<!-- Long HTML contents -->
<script>
// mark: script execution -- inline 4
// Adds a dynamic sync script "?dyn-sync2" throttle=2
</script>
</body></code></pre>
</details>
<details>
<summary>Timeline</summary>
<figure>
<pre>
0.00 <span style="opacity:.5">┬</span> startTime
14.90 <span style="opacity:.5">├</span> requestStart
<span style="opacity:.5">┊</span>
423.10 <span style="opacity:.5">├</span> responseStart
433.80 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">script("…ssets/junk.js?async1")</span>
434.30 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">script("…ssets/junk.js?async2")</span>
434.70 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">script("…/assets/junk.js?def1")</span>
434.80 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">script("…/assets/junk.js?def2")</span>
442.00 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- inline 1</span>
443.00 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">script("…/junk.js?dyn-async-1")</span>
443.60 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- inline 2</span>
443.80 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">script("…/junk.js?dyn-async-2")</span>
444.60 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- inline 3</span>
444.70 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">script("…s/junk.js?dyn-sync-1")</span>
482.40 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-paint</span>
482.40 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-contentful-paint</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
1041.90 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">script("…ssets/junk.js?async1")</span>
1045.20 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- async 1</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
2886.10 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- inline 4</span>
2886.60 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">script("…s/junk.js?dyn-sync-2")</span>
3004.30 <span style="opacity:.5">├</span> responseEnd
3004.90 <span style="opacity:.5">├</span> domInteractive
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
4723.90 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">script("…/assets/junk.js?def2")</span>
<span style="opacity:.5">┊</span>
4921.80 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">script("…s/junk.js?dyn-sync-2")</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
5646.10 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">script("…/junk.js?dyn-async-1")</span>
5647.60 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- dynamic async 1</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
6618.30 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">script("…/assets/junk.js?def1")</span>
6619.60 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- deferred 1</span>
6619.80 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- deferred 2</span>
6619.90 <span style="opacity:.5">├</span> domContentLoadedEventStart
6619.90 <span style="opacity:.5">├</span> domContentLoadedEventEnd
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
7796.70 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">script("…s/junk.js?dyn-sync-1")</span>
7798.10 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- dynamic sync 1</span>
7798.20 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- dynamic sync 2</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
9640.20 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">script("…ssets/junk.js?async2")</span>
9641.60 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- async 2</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
11739.20 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">script("…/junk.js?dyn-async-2")</span>
11740.30 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- dynamic async 2</span>
11740.50 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">callback execution -- onload dynamic async 2</span>
11741.00 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">script("…/junk.js?dyn-async-3")</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
14862.00 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">script("…/junk.js?dyn-async-3")</span>
14863.70 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution -- dynamic async 3</span>
14863.70 <span style="opacity:.5">├</span> domComplete
14863.80 <span style="opacity:.5">├</span> loadEventStart
14863.80 <span style="opacity:.5">└</span> loadEventEnd</pre>
<figcaption>
Timeline: Shows that all async scripts (initials or dynamically added) block nothing and get executed when they are ready. Deferred scripts hold the <code>DOMContentLoaded</code> event, and must wait other deferred scripts to be downloaded before executing. Dynamic sync scripts are executed in the order they where added to the document; in the example the dyn-sync-1 script takes a long time and holds the execution of dyn-sync-2. Finally domComplete won't happen until all pending scripts execute, disregarding how late they where added. In the example dyn-async-2 would have been the last resource, but we added a new script dyn-async-3 in its onload callback, thus posposing the <code>load</code> event.
</figcaption>
</figure>
</details>
<p>[<a href="#toc">TOP</a>]</p>
</article>
<hr>
<article id="basic-html-style-script-inline-async">
<h2>📝 Execute inline scripts without waiting for styles</h2>
<p>We have seen <a href="#basic-html-style-script">that inlined scripts can't execute until the ongoing styles loading ends</a>.</p>
<p>It is possible to overcome that limitation by mocking the inlined script as an external async script, using the <code>src</code> attribute to contain the code as a <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs" target="_blank">data URL</a>. The downside is that the code must be URL encoded. It is not easy to manage.</p>
<p>Note that this method would not be useful if we use <code>defer</code>, given that deferred scripts also await for the ongoing styles to finish loading.</p>
<p><a href="https://esroyo.github.io/pageload-examples/examples/basic-html-style-script-inline-async/" target="_blank"><button>Open example</button></a>
☑
<a href="https://www.webpagetest.org/result/230911_AiDcE1_B12/3/details/" target="_blank">Webpage test result</a>
</p>
<details>
<summary>HTML outline</summary>
<pre><code><head>
<link rel="stylesheet" href="./assets/new.css" throttle="10">
</head>
<body>
<script async src="data:application/javascript,<YOUR_CODE_HERE>"></script>
<!-- alternative as base64
<script async src="data:application/javascript;base64,cGVyZm9ybWFuY2UubWFyaygnc2NyaXB0IGV4ZWN1dGlvbicp"></script>
-->
<!-- Long HTML contents -->
</body></code></pre>
</details>
<details>
<summary>Timeline</summary>
<figure>
<pre>
0.00 <span style="opacity:.5">┬</span> startTime
14.70 <span style="opacity:.5">├</span> requestStart
18.00 <span style="opacity:.5">├</span> responseStart
22.10 <span style="opacity:.5">├</span> responseEnd
27.10 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">link("…mples/assets/new.css")</span>
34.10 <span style="opacity:.5">├</span> mark: <span style="opacity:.6">script execution</span>
34.20 <span style="opacity:.5">├</span> domInteractive
34.20 <span style="opacity:.5">├</span> domContentLoadedEventStart
34.20 <span style="opacity:.5">├</span> domContentLoadedEventEnd
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
10446.10 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">link("…mples/assets/new.css")</span>
10498.40 <span style="opacity:.5">├</span> domComplete
10498.50 <span style="opacity:.5">├</span> loadEventStart
10498.50 <span style="opacity:.5">├</span> loadEventEnd
10548.10 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-paint</span>
10548.10 <span style="opacity:.5">└</span> paint: <span style="opacity:.6">first-contentful-paint</span></pre>
<figcaption>
Timeline: An style starts to load very early. It blocks the <code>load</code> event, the rendering, and would block inline scripts too. The inline script of the example mocks an external async script behaviour, thus It can execute immediately without waiting for the style to load. Compare it with the <a href="#basic-html-style-script">regular inline script timeline</a>.</p>
</figcaption>
</figure>
</details>
<p>[<a href="#toc">TOP</a>]</p>
</article>
<hr>
<article id="basic-html-load">
<h2>📝 The "load" event fires once all resources in turn have fired "load"</h2>
<p>Most of the resources like scripts (any kind), styles, images, iframes, etc. have a <code>load</code> event (usually alternative exclusive to the <code>error</code> event).</p>
<p>When all the resources of the page <em>currently loading</em> have fired <code>load</code>, then the load event will take place.</p>
<p>Resources that are declared lazy (images or iframes) and have not started loading won't count.</p>
<p><a href="https://esroyo.github.io/pageload-examples/examples/basic-html-load/" target="_blank"><button>Open example</button></a>
☑
<a href="https://www.webpagetest.org/result/230911_BiDc6S_B80/1/details/" target="_blank">Webpage test result</a>
</p>
<details>
<summary>HTML outline</summary>
<pre><code><head>
<link rel="stylesheet" href="./assets/inter.css">
<link rel="stylesheet" href="./assets/new.css" throttle="2">
</head>
<body>
<img src="./assets/www-letshare.png" />
<!-- Long HTML contents -->
<img loading="lazy" src="./assets/www-letshare.png?lazy" />
<iframe src="./basic-html-style/index.html" onload="performance.mark('iframe loaded')"></iframe>
<iframe loading="lazy" src="../index.html?lazy"></iframe>
</body></code></pre>
</details>
<details>
<summary>Timeline</summary>
<figure>
<pre>
0.00 <span style="opacity:.5">┬</span> startTime
5.70 <span style="opacity:.5">├</span> requestStart
37.40 <span style="opacity:.5">├</span> responseStart
42.60 <span style="opacity:.5">├</span> responseEnd
48.30 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">link("…les/assets/inter.css")</span>
48.60 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">link("…mples/assets/new.css")</span>
48.80 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">img("…ets/www-letshare.png")</span>
54.50 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">iframe("…tml-style/index.html")</span>
56.00 <span style="opacity:.5">├</span> domInteractive
56.00 <span style="opacity:.5">├</span> domContentLoadedEventStart
56.10 <span style="opacity:.5">├</span> domContentLoadedEventEnd
147.40 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">link("…les/assets/inter.css")</span>
148.70 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">iframe("…tml-style/index.html")</span>
151.10 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">img("…ets/www-letshare.png")</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
2234.40 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">link("…mples/assets/new.css")</span>
2237.10 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">css("…ter/Inter-Bold.woff2")</span>
2237.50 <span style="opacity:.5">├</span> resourceStart: <span style="opacity:.6">css("…/Inter-Regular.woff2")</span>
2273.70 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-paint</span>
2273.70 <span style="opacity:.5">├</span> paint: <span style="opacity:.6">first-contentful-paint</span>
2316.90 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">css("…ter/Inter-Bold.woff2")</span>
2323.10 <span style="opacity:.5">├</span> resourceEnd: <span style="opacity:.6">css("…/Inter-Regular.woff2")</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>
<span style="opacity:.5">┊</span>