前端技术就是对规范의정보
什么是DOMContentLoaded事件?
W3C의 HTML5规范,DOMContentLoaded事件에서 什么时候触发:
사용자 에이전트가 문서 구문 분석을 중지하면 사용자 에이전트는 다음 단계를 실행해야 합니다.规范总是那么的晦涩,但至少有一点是可以明确了的,就是在JS(不包括动态插入的JS)执行完之后,才会触发D OMContentLoaded사건。1. 현재 문서 준비 상태를 "대화형"으로 설정하고 삽입 지점을 정의되지 않음으로 설정합니다.
열린 요소 스택에서 모든 노드를 팝합니다.
2. 문서 구문 분석이 완료되었을 때 실행될 스크립트 목록이 비어 있지 않으면 다음 하위 단계를 실행하세요.
2.1 문서 구문 분석이 완료되면 실행될 스크립트 목록의 첫 번째 스크립트에 "파서 실행 준비 완료" 플래그가 설정되고 파서의 문서에 스크립트를 차단하는 스타일 시트가 없을 때까지 이벤트 루프를 회전합니다.
2.2 문서 파싱이 완료되면 실행될 스크립트 목록 중 첫 번째 스크립트를 실행합니다.
2.3 문서 구문 분석이 완료되면 실행될 스크립트 목록에서 첫 번째 스크립트 요소를 제거합니다(예: 목록의 첫 번째 항목 이동).
2.4 문서 구문 분석이 완료되었을 때 실행될 스크립트 목록이 여전히 비어 있지 않으면 하위 단계 1부터 다시 반복하세요.
3. 문서에서
DOMContentLoaded라는 이름의 버블링이 발생하는 간단한 이벤트를 실행하는 작업을 대기열에 추가합니다.
接下来看看
MDN上有关DOMContentLoaded事件的文档:
스타일시트, 이미지 및 하위 프레임 로드가 완료될 때까지 기다리지 않고 문서가 완전히 로드되고 구문 분석되면 DOMContentLoaded 이벤트가 시작됩니다.참고: 스타일시트는 블록 스크립트 실행을 로드하므로
와执行每个静态的script标签中的JS,然后触发。
뒤에<font face="NSimsun"><script></script></font>
가 있으면 스타일시트가 로드될 때까지 페이지 구문 분석이 완료되지 않고 DOMContentLoaded가 실행되지 않습니다.<font face="NSimsun"><link rel="stylesheet" ...></font>
而JS의 활동, 需要等待位于它앞면의 CSS加载(如果是外联的话), 执行完成, 因为JS可能会依赖位于它앞면의 CSS计算轥的样式。
实验1:DOMContentLoaded事件不直接等待CSS文件、图文的加载完成
<font face="NSimsun">interactive</font>
实践是检验真理的唯一标准
index.html:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title></title> <link rel="stylesheet" type="text/css" href="./css/main.css" rel="external nofollow" rel="external nofollow" > </head> <body> <p>Content</p> <img src="./img/chrome-girl.jpg" alt="DOMContentLoaded event_javascript 기술에 대한 JS, CSS 및 img의 영향" > </body> </html>图一
如果页面中没有script标签,DOMContentLoaded事件并没有等待CSS文件、图文加载完成。Chrome 사용자의 타임라인 화면은 내 정보를 바탕으로 제공됩니다.线和绿线分别表示load事件和First 페인트, 호버에서 색상 방향을 아래로 향하게 하는 작은 부분 공유하기를 클릭하세요.
实验2:DOMContentLoaded事件需要等待JS执行完才触发
index.html:
main.js:
console.timeStamp('External script after link in body');
图二
如果页面中静态的写有script标签,DOMContentLoaded事件需要等待JS执行完才触发。
而script标签中的JS需要等待位于其前面的CSS的加载完成。
console.timeStamp() 可以向Timeline中添加一条记录,并对应上方的一条黄线。
从图二中可以看出,在CSS之前的JS立刻得到了执行,而在CSS之后的JS,需要等待CSS加载完后才执行,比较明显的是main.js早就加载完了,但还是要等main.css加载完才能执行。而DOMContentLoaded事件,则是在JS执行完后才触发。滑动Timeline面板中表示展示区域的滑块,如图三,放大后即可看到表示DOMContentLoaded事件的蓝线(之前跟黄线和绿线靠的太近了),当然,通过 console.timeStamp() 向TimeLine中添加的记录也可证明其触发时间。
图三
现代浏览器会并发的预加载CSS, JS,也就是一开始就并发的请求这些资源,但是,执行CSS和JS的顺序还是按原来的依赖顺序(JS的执行要等待位于其前面的CSS和JS加载、执行完)。先加载完成的资源,如果其依赖还没加载、执行完,就只能等着。
实验3:img何时开始解码、绘制?
从图三中我们可以发现一个有趣的地方:img的请求老早就发出了,但延迟了一段时间才开始解码。如图二、图三中的红框所示,截图中只框出了一部分表示解码的记录,而实际上这些表示解码的记录一直持续到img加载结束,如图四所示,img是一边加载一边解码的:
图三
现代浏览器会并发的预加载CSS, JS,也就是一开始就并发的请求这些资源,但是,执行CSS和JS的顺序还是按原来的依赖顺序(JS的执行要等待位于其前面的CSS和JS加载、执行完)。先加载完成的资源,如果其依赖还没加载、执行完,就只能等着。
实验3:img何时开始解码、绘制?
从图三中我们可以发现一个有趣的地方:img的请求老早就发出了,但延迟了一段时间才开始解码。如图二、图三中的红框所示,截图中只框出了一部分表示解码的记录,而实际上这些表示解码的记录一直持续到img加载结束,如图四所示,img是一边加载一边解码的:
图四抱着“猜想——验证”的想法,我猜想这是因为img这个资源是否需要展现出来,需要等 所有的JS和CSS的执行完 才知道,因为main.js可能会执行某些DOM操作,比如删除这个img元素,或者修改其src属性,而CSS可能会将其
<font face="NSimsun">display: none</font>
。
图五
图六
图七图五中没有JS和CSS,img的数据一接收到就马上开始解码了。
图六中没有JS,但img要等到CSS加载完才开始解码。
图七的代码跟图六的代码唯一的区别是CSS把img给<font face="NSimsun">display: none;</font>
,这使得img虽然请求了,但根本没有进行解码。
这说明,img是否需要解码、绘图(paint)出来,确实需要等CSS加载、执行完才能知道。也就是说,CSS会阻塞img的展现!那么JS呢?
图八图八对应的代码:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title></title> <script type="text/javascript"> console.timeStamp('Inline script in head'); window.addEventListener('DOMContentLoaded', function(){ console.timeStamp('DOMContentLoaded event'); }); </script> </head> <body> <p>Content</p> <img src="./img/chrome-girl.jpg" alt="DOMContentLoaded event_javascript 기술에 대한 JS, CSS 및 img의 영향" > <script type="text/javascript" src="./js/main.js"></script> </body> </html>JS는 있지만 CSS는 없는 페이지에서 img가 실제로 데이터를 수신한 후 즉시 디코딩과 그리기(페인트)를 시작할 수 있다는 점은 매우 놀랍습니다. 즉, JS는 img의 표시를 차단하지 않습니다. 이는 JS가 img 리소스를 차단한다는 기존 개념에 대한 이전의 이해와 다릅니다. Chrome은 img의 로딩 및 표시를 위해 새로운 최적화를 만든 것 같습니다.
우리가 일반적으로 사용하는 jQuery의 $(document).ready() 메서드는 DOMContentLoaded 이벤트를 모니터링하는 것입니다(물론 DOMContentLoaded 이벤트를 시뮬레이션하고 onload 이벤트를 모니터링하여 내부적으로 다운그레이드 솔루션도 제공합니다). 일반적으로 DOMContentLoaded 이벤트가 트리거될 때 DOM 요소에 대한 이벤트를 등록하는 것이 좋습니다. 따라서 가능한 한 빨리 DOMContentLoaded 이벤트를 트리거한다는 것은 페이지가 가능한 한 빨리 대화형이 될 수 있다는 것을 의미합니다.
CSS 파일 크기를 줄이고, 병렬 로딩을 위해 단일 CSS 파일을 여러 파일로 나누고, JS에서 CSS 차단 시간을 줄입니다
보조 JS 파일은 동적으로 스크립트 태그를 삽입하여 로드됩니다. (동적으로 삽입된 스크립트 태그는 DOMContentLoaded 이벤트의 트리거를 차단하지 않습니다.)
CSS에 사용되는 스프라이트는 img를 미리 로드하여 HTML의 CSS 파일과 함께 로드할 수 있습니다.
실험을 진행하면서 Chrome 개발자 도구의 타임라인 패널이 매우 강력하고 브라우저의 모든 움직임이 기록된다는 것을 느꼈습니다. 과거에는 프런트 엔드 개발에서 브라우저의 내부 동작을 이해하고 탐색하려면 돌을 만져 보면서 블랙박스 테스트를 수행하거나 두 배의 결과와 절반의 노력으로 브라우저 소스 코드를 연구했습니다. 유일한 효율적인 방법은 다른 사람의 연구 경험에서 배우고 외국인의 연구 경험 기사를 보는 것이었지만 브라우저의 개발은 날이 갈수록 변화하고 있습니다(예를 들어 이 실험에서 발견된 JS는 img 표시를 차단하지 않습니다. ), 다른 사람의 경험은 결코 최신의 것이 아니며 가장 적합한 것이 아닙니다. 핵심은 자신의 비즈니스와 수요 시나리오를 결합하고 목표에 맞는 결정을 내리는 것입니다. 분석 및 최적화.
PS.
위 테스트 환경은 windows/chrome이며, 느린 네트워크를 시뮬레이션하기 위해 Fiddler를 사용했습니다