>웹 프론트엔드 >JS 튜토리얼 >JavaScript 비차단 로딩 성능 최적화를 위한 샘플 코드 공유

JavaScript 비차단 로딩 성능 최적화를 위한 샘플 코드 공유

黄舟
黄舟원래의
2017-03-16 15:15:371329검색

브라우저에서의

Javascript 성능은 프론트엔드 개발자가 직면하는 가장 중요한 사용성 문제라고 할 수 있습니다.

Yahoo의 Yslow 23 규칙 중 하나는 JS를 하단 에 넣는 것입니다. 그 이유는 사실 대부분의 브라우저가 단일 프로세스를 사용하여 UI, 업데이트Javascript 실행 등 여러 작업을 처리하고, 동시에 하나의 작업만 실행할 수 있기 때문입니다. Javascript가 실행되는 시간과 브라우저가 사용자 상호 작용에 응답하기 위해 유휴 상태가 될 때까지 기다리는 시간입니다.

기본적으로 이는 3f1c4e4b6b16bbbd69b2ee476dc4f83a 태그가 나타나면 전체 페이지가 스크립트가 구문 분석되고 실행될 때까지 기다리게 된다는 의미입니다. 실제 JavaScript 코드가 인라인인지 관련 없는 외부 파일에 포함되어 있는지에 관계없이 페이지 다운로드 및 구문 분석 프로세스는 계속하기 전에 스크립트가 이 처리를 완료할 때까지 중지하고 기다려야 합니다. 스크립트가 실행되는 동안 페이지 콘텐츠를 수정할 수 있으므로 이는 페이지 수명 주기 의 필수 부분입니다. 일반적인 예는 document.write()function입니다. 예:

 1 <html>
 2   <head>
 3     <title>Script Example</title>
 4   </head> 
 5   
 6   <body>
 7      <p>
 8         <script type="text/javascript">
 9            document.write("The date is " + (new Date()).toDateString());
10         </script> 
11      </p>
12   </body> 
13 </html>

위의 HTML 페이지에서와 같이 브라우저가 3f1c4e4b6b16bbbd69b2ee476dc4f83a 이렇게 하면 JavaScript가 e388a4556c0f65e1904146cc1a846bee 태그에 콘텐츠를 추가할지 여부를 예측하는 것이 불가능합니다. 따라서 브라우저는 중지되고 이 JavaScript 코드를 실행한 다음 페이지 구문 분석 및 번역을 계속합니다. src 속성을 사용하여 JavaScript를 로드할 때도 동일한 일이 발생합니다. 브라우저는 먼저 외부 파일용 코드를 다운로드해야 하는데, 이 작업에는 시간이 좀 걸립니다. 그런 다음 코드를 구문 분석하고 실행합니다. 이 과정에서 페이지 구문 분석 및 사용자 상호 작용이 완전히 차단됩니다.

스크립트는 다른 페이지 리소스의 다운로드 프로세스를 차단하므로 권장되는 접근 방식은 모든 3f1c4e4b6b16bbbd69b2ee476dc4f83a 태그를 6c04bd5ca3fcae76e30b72ad730ca86d 태그 하단에 최대한 가깝게 배치하여 다운로드에 미치는 영향을 최소화하는 것입니다. 전체 페이지에 영향을 줍니다. 예:

 1 <html>
 2   <head>
 3     <title>Script Example</title>
 4     <link rel="stylesheet" type="text/css" href="styles.css"> 
 5   </head>
 6   
 7   <body>
 8     <p>Hello world!</p>
 9     <-- Example of recommended script positioning --> 
10       <script type="text/javascript" src="file1.js"></script> 
11       <script type="text/javascript" src="file2.js"></script> 
12       <script type="text/javascript" src="file3.js"></script>
13   </body> 
14 </html>

이 코드는 HTML 파일에서 3f1c4e4b6b16bbbd69b2ee476dc4f83a 태그의 권장 위치를 ​​보여줍니다. 스크립트 다운로드가 서로 차단되기는 하지만 페이지가 다운로드되어 사용자 앞에 표시되므로 페이지 진입 속도가 크게 느리지는 않습니다. 위에서 언급한 JS를 맨 아래에 배치한 내용입니다.

또한 Yahoo!는 "Content Delivery Network"(Content Delivery Network)를 통해 "Yahoo! User Interface (Yahoo! User Interface, YUI)" 라이브러리에 대한 "결합 핸들"을 만듭니다. 네트워크, CDN)'이 구현되었습니다. 모든 웹사이트는 "통합 핸들" URL을 사용하여 YUI 패키지에 포함된 파일을 나타낼 수 있습니다. 예를 들어, 다음 URL에는

<script type="text/javascript" 
src=" 
</script>

라는 두 개의 파일이 포함되어 있습니다. 이 URL은 yahoo-min.js 및 event-min.js 파일의 2.7.0 버전을 호출합니다. 이 파일은 서버에 있는 두 개의 별도 파일이지만 서버가 이 URL 요청을 받으면 두 파일이 함께 병합되어 클라이언트에 반환됩니다. 이런 방식으로 두 개의 3f1c4e4b6b16bbbd69b2ee476dc4f83a 태그(각각 파일 로드)가 필요하지 않으며 하나의 3f1c4e4b6b16bbbd69b2ee476dc4f83a 태그를 로드할 수 있습니다. 이는 HTML 페이지에 여러 외부 Javascript를 포함하는 가장 좋은 방법입니다.

Noblocking 스크립트

위 내용은 페이지의 초기

상태에서 여러 Javascript 스크립트를 로드하는 가장 좋은 방법입니다. Javascript는 개발자가 직면한 가장 심각한 성능 문제인 http 요청 및 인터페이스 새로 고침과 같은 특정 브라우저 프로세스를 차단하는 경향이 있습니다. JavaScript 파일을 짧게 유지하고 http 요청 수를 제한하는 것은 반응형 웹 애플리케이션을 만드는 첫 번째 단계일 뿐입니다. 그러나 JS 코드가 많은 대규모 웹페이지와 같이 소스 코드를 짧게 유지하는 것이 항상 최선의 선택은 아닙니다. 그래서 비차단 스크립트가 등장하게 되었습니다. 브라우저를 어느 정도 차단하지 않고 페이지에 자바스크립트를 점진적으로 추가하는 것이 필요합니다.

스크립트를 차단하지 않는 핵심은 자바스크립트 소스 코드를 로드하기 전에 페이지 로드가 완료될 때까지 기다리는 것입니다. 즉, 창의 로드

이벤트

가 발생한 후 코드 다운로드를 시작한다는 의미입니다.

관련 설명:

창의 로드 이벤트는 페이지가 로드된 후 한 번만 발생합니다.

window.

onload

=function(){}은 웹 페이지의 모든 콘텐츠가 로드될 때까지 기다려야 합니다(image와 같은 요소의 모든 관련 파일 포함). )이 실행되기 전에 즉, Javascript는 현재 페이지의 모든 요소에 액세스할 수 있습니다.

다음 방법은 다음과 같습니다.

Deferred Scripts 延期脚本

Html4为3f1c4e4b6b16bbbd69b2ee476dc4f83a标签定义了一个扩展属性:defer。

这个defer属性指明元素中所包含的脚本不打算修改DOM,因此代码可以稍后执行。defer属性只被Internet Explorer 4+和Firefox 3.5+支持,它不是一个理想的跨浏览器解决方案。在其他浏览器上,defer属性将被忽略。所以,3f1c4e4b6b16bbbd69b2ee476dc4f83a标签会按照正常默认方式处理,即是会造成阻塞。如果得到各个主流浏览器的支持,这仍是一种有效的解决方式。

<script type="text/javascript" src="file1.js" defer></script>

一个带有defer属性的3f1c4e4b6b16bbbd69b2ee476dc4f83a标签可以放置在文档的任何位置,它会在被解析时启动下载,直到DOM加载完成(在onload事件句柄被调用之前)。当一个defer的Javascript文件被下载时,它不会阻塞浏览器的其他处理过程,所以这些文件可以与其他资源一起并行下载。

可以使用下述代码测试浏览器是否支持defer属性:

 1 <html>
 2   <head>
 3     <title>Script Defer Example</title>
 4   </head> 
 5 
 6   <body>
 7     <script defer> alert("defer");</script> 
 8     <script> alert("script"); </script> 
 9     <script> window.onload = function(){ alert("load");}; </script>
10   </body> 
11 </html>

如果浏览器不支持defer,那么弹出的对话框的顺序是“defer”,“script”,“load”。

如果浏览器支持defer,那么弹出的对话框的顺序是“script”,“load”,“defer”。

Dynamic Script Elements 动态脚本元素

DOM允许我们使用Javascript动态创建HTML的几乎所有文档内容,一个新的3f1c4e4b6b16bbbd69b2ee476dc4f83a元素可以非常容易的通过标准DOM创建:

1 var script = document.createElement ("script");
2 script.type = "text/javascript";
3 script.src = "file1.js"; 
4 document.body.appendChild(script);

新的3f1c4e4b6b16bbbd69b2ee476dc4f83a元素加载file1.js源文件。此文件当元素添加到页面后立刻开始下载。此技术的重点在于:无论在何处启动下载,文件的下载和运行都不会阻塞其他页面处理过程。

当文件使用动态脚本节点下载时,返回的代码通常立即执行(除了Firefox和Opera,它们将等待此前的所有动态脚本节点执行完毕)。

大多数情况下,我们希望调用一个函数就可以实现Javascript文件的动态下载。下面的函数封装实现了标准实现和IE实现:

 1  function loadScript(url, callback){
 2     var script = document.createElement ("script") ;
 3    script.type = "text/javascript";
 4      
 5     if (script.readyState){ //IE
 6        script.onreadystatechange = function(){
 7          if (script.readyState == "loaded" || script.readyState == "complete"){
 8            script.onreadystatechange = null;
 9            callback(); 
10           }
11        };
12      } 
13      else { //Others
14        script.onload = function(){ callback();
15      }; 
16    }
17    script.src = url;
18    document.getElementsByTagName("head")[0].appendChild(script); 
19  }
20 
21 loadScript("file1.js", function(){  //调用
22     alert("File is loaded!"); 
23 });

此函数接受两个参数:Javascript文件的Url和一个当Javascript接收完成时触发的回调函数。属性检查用于决定监视哪种事件。最后一步src属性,并将javascript文件添加到head。

动态脚本加载是非阻塞Javascript下载中最常用的模式,因为它可以跨浏览器,而且简单易用。

XMLHttpRequest Script Injection XHR脚本注入

另一个以非阻塞方式获得脚本的方法是使用XMLHttpRequest(XHR)对象将脚本注入到页面中。此技术首先创建一个XHR对象,然后下载Javascript文件,接着用一个动态3f1c4e4b6b16bbbd69b2ee476dc4f83a元素将Javascript代码注入页面。看demo:

 1 var xhr = new XMLHttpRequest(); 
 2 xhr.open("get", "file1.js", true); 
 3 xhr.onreadystatechange = function(){
 4     if (xhr.readyState == 4){
 5       if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ // 检查http状态码
 6         var script = document.createElement("script"); 
 7         script.type = "text/javascript";
 8         script.text = xhr.responseText;
 9         document.body.appendChild(script);
10       } 
11    }
12 }; 
13 xhr.send(null);

此代码向服务器发送一个获取file1.js的文件get请求。onreadystatechange事件处理函数检查readyState是不是4,然后检查HTTP状态码是不是有效(200表示确定客户端请求已成功,2xx表示有效回应,304表示一个缓存响应)。如果收到一个有效响应,那么就创建一个新的3f1c4e4b6b16bbbd69b2ee476dc4f83a元素,将它的文本属性设置为从服务器接收到的responseText字符串。这样做实际上会创建一个带有内联代码的3f1c4e4b6b16bbbd69b2ee476dc4f83a元素,一旦新的3f1c4e4b6b16bbbd69b2ee476dc4f83a元素被添加到文档,代码将被执行,并准备使用。

此方法的优点是兼容性佳,且你可以下载不立即执行的Javascript代码。由于代码返回在3f1c4e4b6b16bbbd69b2ee476dc4f83a标签之外,它下载后不会自动执行,这使得你可以推迟执行。

此方法的确定是受到浏览器同源限制,Javascript文件必须与页面放置在同一个域内,不能从CDN(内容分发网络Content Delivery Network)下载。正因为这个原因,大型网页通常不采用XHR脚本注入技术。

Recommended Noblocking Pattern 推荐的非阻塞模式

推荐的向页面加载大量Javascript的方法分为两个步骤:

  • 第一步,包含动态加载Javascript所需的代码,然后加载页面初始化所需的除了Javascript之外的部分。这部分代码尽量小,可能只包含loadScript()函数,它的下载和运行非常迅速,不会对页面造成很大干扰。

  • 第二步,当初始代码准备好之后,用它来加载其余的Javascript。

例如:

1 <script type="text/javascript" src="loader.js">
2 </script> <script type="text/javascript">
3 loadScript("the-rest.js", function(){ 
4   Application.init();
5 }); 
6 
7 </script>

将此代码放置在body的关闭标签36cc49f0c466276486e50c850b7e4956之前。这样做的好处是,首先,这样确保Javascript运行不会影响其他页面的其他部分显示。其次,当第二部分Javascript文件完成下载,所有应用程序所必须的DOM已经创建完毕,并做好被访问的准备,避免使用额外的事件处理(如window.onload)来得知页面是否已经准备好了。

另一个选择是直接将loadScript()函数嵌入在页面中,这可以减少一个http请求的开销。例如:

 1 <script type="text/javascript"> 
 2   function loadScript(url, callback){
 3     var script = document.createElement ("script");
 4    script.type = "text/javascript";
 5    
 6     if (script.readyState){ //IE script.onreadystatechange = function(){
 7       if (script.readyState == "loaded" || script.readyState == "complete"){
 8         script.onreadystatechange = null; 
 9         callback();
10       } 
11     };
12   } else { //Others 
13    script.onload = function(){
14      callback(); 
15    };
16   }
17   script.src = url; 
18   document.getElementsByTagName("head")[0].appendChild(script);
19 }
20 
21 loadScript("the-rest.js", function(){
22   Application.init(); 
23 });
24 </script>

一旦页面初始化代码下载完成,还可以使用loadScript()函数加载页面所需的额外功能函数。

介绍一个通用的工具,Yahoo! Search的Ryan Grove创建了LazyLoad库。LazyLoad是一个强大的loadScript()函数。LazyLoad精缩之后只有大约1.5KB。用法举例如下:

1 <script type="text/javascript" src="lazyload-min.js"></script> 
2 <script type="text/javascript">
3   LazyLoad.js("the-rest.js", function(){ 
4     Application.init();
5   }); 
6 </script>

Summary 总结

  • 将所有3f1c4e4b6b16bbbd69b2ee476dc4f83a标签放置在页面底部,紧靠关闭标签36cc49f0c466276486e50c850b7e4956的上方。此方法可以保证页面在脚本运行之前完成解析。

  • 将脚本成组打包。页面的3f1c4e4b6b16bbbd69b2ee476dc4f83a标签越少,页面的加载速度就越快,响应也更迅速。不论外部脚本文件还是内联代码都是如此。

  • 有几种方法可以使用非阻塞方式下载Javascript:

    • 为3f1c4e4b6b16bbbd69b2ee476dc4f83a标签添加defer属性

    • 动态创建3f1c4e4b6b16bbbd69b2ee476dc4f83a元素,用它下载并执行代码

    • 用XHR对象下载代码,并注入到页面

通过上述策略,可以极大提高那些使用Javascript代码的网友应用的实际性能。

위 내용은 JavaScript 비차단 로딩 성능 최적화를 위한 샘플 코드 공유의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.