ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [자바스크립트 성능 최적화] Ch01. 로딩과 실행
    Study/BookNotes 2021. 3. 4. 15:47

    브라우저 대부분은 한 프로세스에서 UI 업데이트와 JavaScript 실행을 동시에 수행할 수 없다

    JS코드가 <script> 안에 있든, 외부 파일에 있든 해당 처리가 끝날 때까지 렌더링 등 다른 작업은 중단됨

    HTML5, 최신 브라우저에서도 그러한가?

    - 동시 다운로드 자체는 지원하지만 pure한 <script>에서는 작업이 중단됨
    - defer (지연 스크립트) 또는 async (비동기 스크립트) 옵션이 있는 경우, 병렬 다운로드 가능함

    참고 : 
    - defer, async 스크립트
    - 스크립트 요소

     

    스크립트의 위치

    <head>에서 여러 개의 JS을 로딩하는 경우

    1. 첫번째 JS 파일 가져오기 위한 HTTP request
    2. 첫번째 JS 파일 다운로드
    3. 첫번째 JS 파일 실행
    4. 두번째 JS 파일 가져오기 위한 HTTP request

    이런 순서로 진행되며, 각 과정을 진행하면서 이미지 다운로드, 렌더링 등 다른 작업은 중단됨

    따라서 모든 <script>는 <body> 마지막에 배치해서 페이지 전체를 내려받는 것에 영향 주지 않도록 하는 것을 권장

     

    인라인 스크립트가 <link> 다음에 위치할 경우

    스타일시트를 완전히 다운로드할 때까지 인라인 스크립트 실행 차단됨

    따라서 인라인 스크립트는 <link> 다음에 놓지 않는 것을 권장


    스크립트 묶기

    외부 JS를 가져오려면 HTTP 요청해야 하고, 이 때마다 성능 부담 증가

    따라서 25kb 4개 가져올 때보다 100kb 1개 가져올떄가 더 빠름


    비차단 스크립트 nonblocking script

    그런데 대형 웹에서는 이렇게 하나로 스크립트를 묶더라도 bundling된 JS파일이 커지는 문제가 있음

    브라우저 프로세스를 차단하지 않으면서 JS를 점진적으로 불러오는 방법이 필요

    페이지를 완전히 불러온 다음 JS 소스를 불러와야 함

    • window.onload 이벤트 발생 이후 코드 로딩

    지연 스크립트; defer

    • 책 발간 당시에는 IE/Firefox만 지원한 기능이지만, 현재는 모든 브라우저에서 지원
    • Syntax: <script defer type="text/javascript" src="..."></script>
    • <script> 만나는 순간부터 소스 로딩되고, DOM 완전히 로드된 이후에 실행
      • onload 이벤트 핸들러 호출 전 실행
      • 브라우저의 다른 프로세스를 차단하지 않음
    • 인라인 스크립트, 외부 스크립트 파일 모두 동일하게 작동

    동적 <script> 태그

    • 동적으로 생성한 script를 페이지에 추가하는 순간부터 파일 로딩하고 바로 실행
    • 따라서 독립실행 코드라면 문제 없지만, 인터페이스만 있는 코드라면 문제 가능성
    • script.onload (IE의 경우 script.readyState에 따라 분기)

    XMLHttpRequest 스크립트 삽입

    HTML5에서 XMLHttpRequest 보다 성능이 좋고 사용하기 편한 fetch가 추가됨!
    책에서는 XMLHttpRequest로 설명하지만 실습은 fetch로 진행함
    • CORS 이슈 때문에 대형 웹에서는 사용하지 않음
    • JS 코드를 내려받지만 즉시 실행하지는 않음

    예시

    <html>
      <head>
        <meta charset="UTF-8" />
        <script defer type="text/javascript" src="defer.js"></script>
      </head>
    
      <body>
        <h1>Hello there!</h1>
    
        <script>
          function loadScript(url, callback) {
            var script = document.createElement("script");
            script.type = "text/javascript";
    
            // IE
            if (script.readyState) {
              script.onreadystatechange = () => {
                if (
                  script.readyState === "loaded" ||
                  script.readyState === "complete"
                ) {
                  script.onreadystatechange = null;
                  callback();
                }
              };
            }
            // other browsers
            else {
              script.onload = function() {
                callback();
              };
            }
    
            script.src = url;
            document.head.appendChild(script);
          }
    
          loadScript("dynamic.js", function() {console.log("dynamic script loaded!!")})
        </script>
    
        <script>
          var url = "fetch.js";
          var type = "text/javascript";
          var headers = new Headers();
          headers.append("Content-Type", type);
          var initOptions = {
            method: "GET",
            headers
          };
          fetch(url, headers)
            .then(function(res) {
              console.log("fetched data loaded!!");
              return res;
            })
            .then(function(data) {
              var script = document.createElement("script");
              script.type = type;
              script.src = url;
              document.head.appendChild(script);
            });
        </script>
    
        <script>
          console.log("pure script!");
        </script>
    
        <script>
          window.onload = () => {
            console.log("onload!");
          };
        </script>
      </body>
    </html>
    

     


    추천하는 비차단 패턴

    JS 파일 크기가 큰 경우

    1. 최소한의 크기로 동적 로딩 코드 작성 또는 lazy loading 관련 라이브러리 사용
    2. 나머지 JS 파일 불러오는 코드 로딩
    <html>
      <head>
        <meta charset="UTF-8" />
      </head>
    
      <body>
        <h1>Hello there!</h1>
    
        <script>
          function loadScript(url, callback) {
            var script = document.createElement("script");
            script.type = "text/javascript";
    
            if (script.readyState) {
              script.onreadystatechange = function() {
                if (
                  script.readyState === "loaded" ||
                  script.readyState === "complete"
                ) {
                  script.onreadystatechange = null;
                  callback();
                }
              };
            } else {
              script.onload = function() {
                callback();
              };
            }
          }
    
          loadScript("rests.js", function() {
            app.init();
          });
        </script>
      </body>
    </html>
    

     

    댓글

Designed by Tistory.