브라우저는 HTML 페이지 렌더링 및 JavaScript 스크립트 실행을 처리할 때 단일 프로세스를 사용하므로 브라우저가 HTML을 렌더링하는 동안 <script> 로드된 외부 링크 파일이 먼저 다운로드된 후 실행됩니다. 이 과정에서 페이지 렌더링 및 상호 작용이 차단됩니다. </p> <p>...차단이 있더라도 JavaScript가 성능에 미치는 영향을 줄이는 방법은 여전히 여러 가지가 있습니다. </p> <p><strong>1. 스크립트 태그 위치</strong></p> <p></p>에 <script>가 나타나는 경우: <div class="jb51code"> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false"> <head> <script type="text/javascript" src="js1.js"></script> <script type="text/javascript" src="js2.js"></script> <script type="text/javascript" src="js3.js"></script> </head> </pre><div class="contentsignin">로그인 후 복사</div></div> </div> <p>여러 js 파일을 로드할 때 브라우저는 먼저 js 코드를 다운로드하고 실행하여 페이지 렌더링을 차단하고 결과적으로 흰색 화면 페이지를 표시합니다(브라우저는 <body> 태그를 구문 분석할 때까지 페이지의 콘텐츠를 렌더링하지 않습니다). ) ) 미리 보거나 상호 작용할 수 있는 방법이 없습니다. 이는 매우 열악한 사용자 경험입니다. </p> <p><strong>참고:</strong></p> <p>최신 브라우저는 외부 리소스만 다운로드하는 경우 다른 <script> 태그를 차단하지 않지만 다른 리소스의 다운로드는 차단합니다. <br /> JavaScript 리소스 다운로드는 비동기식이지만 JavaScript 코드 실행은 여전히 동기식이므로 차단도 발생합니다. <br /> 따라서 스크립트를 실행하기 전에 페이지 렌더링이 완료되었는지 확인하기 위해 <body> 태그 하단에 <script>를 배치하는 것이 비교적 일반적인 JavaScript 최적화 방법입니다. </p> <p><strong>2. 여러 스크립트 태그 병합 </strong></p> <p>브라우저가 HTML을 구문 분석하고 <script>를 발견하면 스크립트 실행으로 인해 특정 지연이 발생합니다. src 속성이 있는 외부 링크의 경우 다중 HTTP 요청이 발생하면 더욱 악화됩니다. 더 많은 성능 오버헤드를 최소화하는 것도 최적화 방법입니다. 여러 js 파일을 병합하여 HTTP 요청 수를 줄이고, 3방향 핸드셰이크 및 중복 HTTP 헤더 전송 수를 줄이고, 응답 시간을 줄이고, 사용자 경험을 향상시킬 수 있습니다. 인터넷에는 js를 병합하기 위한 많은 솔루션과 도구가 있지만 여기서는 설명하지 않습니다. </p> <p><strong>3. 비차단 방식을 사용하여 JavaScript를 다운로드합니다</strong></p> <ol> <li>스크립트 태그의 defer 및 async 속성을 사용하세요</li> <li>동적으로 생성된 스크립트 태그를 사용하여 JavaScript 코드를 다운로드하고 실행합니다</li> <li>XHR 개체를 사용하여 JavaScript 코드를 다운로드하고 페이지에 삽입<br /> </li> </ol> <p>3.1. 스크립트 태그의 defer 및 async 속성을 사용하세요</p> <p>async 및 defer 속성은 모두 js 파일을 비동기식으로 로드하는 데 사용되며 프로세스 중에 다른 브라우저 프로세스를 차단하지 않습니다. 차이점은 비동기는 로드 후 자동으로 실행되는 반면, defer는 페이지가 로드되기 전에 기다려야 한다는 것입니다. 한 가지 중요한 점은 이 두 속성이 src 속성(외부 링크 스크립트)과 함께 <script> 태그에 있어야 한다는 것입니다. 아래는 데모입니다:</p> <div class="jb51code"> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false"> <!DOCTYPE html> <html> <head> <title>defer example</title> </head> <body> <script type="text/javascript" src="defer.js" defer></script> <script> alert("script"); </script> <script> window.onload= function(){ alert("load"); } </script> <div class="demo">defer demo</div> <div class="demo">defer demo</div> <div class="demo">defer demo</div> <div class="demo">defer demo</div> <div class="demo">defer demo</div> <div class="demo">defer demo</div> <div class="demo">defer demo</div> <div class="demo">defer demo</div> <div class="demo">defer demo</div> <div class="demo">defer demo</div> <div class="demo">defer demo</div> <div class="demo">defer demo</div> </body> </html> </pre><div class="contentsignin">로그인 후 복사</div></div> </div> <p>//defer.js 파일에는 한 줄의 코드만 있습니다: 경고("defer") <br /> 비동기 예제도 동일한 페이지 구조를 가지고 있습니다. 여기서는 예제를 표시하지 않겠습니다. 아래 링크를 클릭하세요. <br /> <a target="_blank" href="http://www.jb51.net/article/44323.htm">예시를 연기하려면 여기를 클릭하세요!</a><br /> <a target="_blank" href="http://www.jb51.net/article/33277.htm">비동기 예시 링크를 보려면 여기를 클릭하세요!</a><br /> </p> <p>페이지 구조는 동일하지만 차이점은 </p> <p>defer.html을 열면 다음이 표시됩니다. "script" 경고 상자가 나타납니다 => 페이지가 텍스트를 렌더링합니다 => "defer" 경고 상자가 나타납니다 => "load" 경고 상자가 나타납니다. 팝업 <br /> async.html을 열면 다음이 표시됩니다. "script"에 대한 경고 상자가 나타납니다 => "async"에 대한 경고 상자가 나타납니다 => 페이지가 텍스트를 렌더링합니다 => "load"에 대한 경고 상자가 나타납니다. <br /> </p> <p>3.2. 동적으로 생성된 스크립트 태그를 사용하여 JavaScript 코드를 다운로드하고 실행합니다</p> <div class="jb51code"> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;"> var script = document.createElement("script"); script.type = "text/javascript"; script.src = "file.js"; document.getElementByTagName("head")[0].appendChild(script); </pre><div class="contentsignin">로그인 후 복사</div></div> </div> <p>file.js는 스크립트 요소가 페이지에 추가되면 다운로드를 시작합니다. 이 방법을 사용하면 file.js를 다운로드하고 실행해도 페이지의 다른 프로세스가 차단되지 않는다는 이점이 있습니다. </p> <p>동적 로딩 방법은 경고 상자가 나타나기 전에 페이지의 텍스트를 볼 수 있지만 일반적인 방법은 경고 상자가 나타난 후에만 페이지의 텍스트를 볼 수 있다는 것을 데모에서 분명히 알 수 있습니다. </p> <p>스크립트 스크립트를 읽고 동적으로 스크립트 태그를 생성하는 크로스 브라우저 기능을 캡슐화할 수 있습니다.</p> <div class="jb51code"> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;"> function loadScript(url,callback){ var script = document.createElement("script"); script.type = "text/javascript"; //检测客户端类型 if(script.readyState){//IE script.onreadystatechange = function(){ if(script.readyState==="loaded"||script.readyState==="complete"){ script.onreadystatechange = null; callback(); } } }else{//其他浏览器 script.onload = function(){ callback(); } } script.src = url; document.getElementsByTagName("head")[0].appendChild(script); } </pre><div class="contentsignin">로그인 후 복사</div></div> </div> <p>이러한 유형의 동적 스크립트 로딩 방법은 호환성이 좋고 비교적 간단하며 일반적으로 사용되는 비차단 솔루션입니다. </p> <p>3.3. XHR 개체를 사용하여 JavaScript 코드를 다운로드하고 페이지에 삽입합니다. </p> <p>차단하지 않고 스크립트를 로드하는 또 다른 방법은 XMLHttpRequest(XHR) 개체를 사용하여 스크립트를 가져와 페이지에 삽입하는 것입니다. <br /> 이 기술은 먼저 XHR 개체를 생성한 다음 이를 사용하여 JavaScript 파일을 다운로드하고 마지막으로 공통 동적 <script> 요소를 통해 페이지에 코드를 삽입합니다. </p> <div class="jb51code"> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;"> var xhr = new XMLHttpRequest(); xhr.open("get","file.js",true); xhr.onreadystatechange = function(){ if(xhr.readyState===4){ if(xhr.status>=200&&xhr.status<300||xhr.status==304){ var script = document.createElement("script"); script.type = "text/javascript"; script.text = xhr.responseText; document.body.appendChild(script); } } } </pre><div class="contentsignin">로그인 후 복사</div></div> </div> <p>以上代码发送GET请求file.js文件,onReadyStateChange检测readyState是否为4(4表示请求完成)和HTTP状态吗是否有效(200表示有效响应,304表示读取缓存)。判断响应有效之后,就动态创建一个<script>标签,内容就是服务器接收到的responseText。</p> <p>这种方法的优点以及缺点:</p> <p>优点:下载JavaScript代码可以不立即执行,且兼容性好适合所有主流浏览器。<br /> 缺点:JavaScript文件必须与所请求页面处于同一个域,这种情况下JavaScript文件不能从CDN下载,不适合大型的Web应用。<br /> </p> <p><strong>4.一种推荐的无阻塞方案</strong></p> <p>如果页面有大量的JavaScript代码需要添加,可以先在页面中去外链之前我们封装好的动态读取script脚本的函数loadScript,然后再使用它去加载其他所需脚本,例如:</p> <div class="jb51code"> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;"> <script type="text/javascript" src="loader.js"></script> <script type="text/javascript"> loadScript("file.js",function(){ //do something }); </script> </pre><div class="contentsignin">로그인 후 복사</div></div> <p>这样只需在第一个<script>下载比较精简的loader.js文件时对页面有些许影响,之后的<script>并不会有太多影响。 </script>