서드 파티 자바스크립트 최적화

서드 파티 스크립트는 성능에 영향을 미치므로 서드 파티 스크립트를 정기적으로 감사하고 효율적인 로드 기술을 사용하는 것이 중요합니다. 이 Codelab에서는 서드 파티 리소스의 로드를 최적화하는 방법을 보여줍니다. 여기에서는 다음과 같은 기법을 다룹니다.

  • 스크립트 로드 지연

  • 중요하지 않은 리소스 지연 로드

  • 필수 출처에 사전 연결

포함된 샘플 앱에는 서드 파티 소스에서 제공하는 세 가지 기능이 있는 간단한 웹페이지가 있습니다.

  • 동영상 삽입

  • 선 그래프를 렌더링하기 위한 데이터 시각화 라이브러리

  • 소셜 미디어 공유 위젯

를 통해 개인정보처리방침을 정의할 수 있습니다. <ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">서드 파티 리소스가 강조표시된 페이지의 스크린샷</ph>
샘플 앱의 서드 파티 리소스

먼저 앱 성능을 측정한 다음 각 기법을 적용하여 앱 성능의 다양한 측면을 개선합니다.

성능 측정

먼저 전체 화면 뷰에서 샘플 앱을 엽니다.

  1. 수정할 리믹스를 클릭하여 프로젝트를 수정할 수 있도록 합니다.
  2. 사이트를 미리 보려면 앱 보기를 누릅니다. 그런 다음 전체 화면 전체 화면입니다.

페이지에서 Lighthouse 성능 감사를 실행하여 기준 성능을 설정합니다.

  1. `Control+Shift+J` (또는 Mac의 경우 `Command+Option+J`)를 눌러 DevTools를 엽니다.
  2. Lighthouse 탭을 클릭합니다.
  3. 모바일을 클릭합니다.
  4. 성능 체크박스를 선택합니다. 감사 섹션에서 나머지 체크박스를 선택 해제할 수 있습니다.
  5. 시뮬레이션된 빠른 3G, 4배 CPU 속도 저하를 클릭합니다.
  6. 저장용량 비우기 체크박스를 선택합니다.
  7. 감사 실행을 클릭합니다.

컴퓨터에서 감사를 실행할 때 정확한 결과는 다를 수 있지만 첫 콘텐츠 페인트 (FCP) 시간이 매우 높으며 Lighthouse에서 두 가지 조사 기회를 제안합니다. 바로 렌더링 차단 리소스 제거필수 출처 사전 연결입니다. (측정항목이 모두 녹색으로 표시되어 있더라도 최적화를 통해 계속 개선이 가능합니다.)

2.4초의 FCP와 2가지 기회를 보여주는 Lighthouse 감사 스크린샷: 렌더링 차단 리소스 제거 및 필수 출처에 사전 연결

서드 파티 JavaScript 지연

d3js.org에서 전송되는 스크립트를 지연시켜 시간을 절약할 수 있는 것으로 확인된 렌더링 차단 리소스 제거 감사:

d3.v3.min.js 스크립트가 강조 표시된 렌더링 차단 리소스 감사 제거 스크린샷

D3.js는 데이터 시각화를 만들기 위한 JavaScript 라이브러리입니다. 샘플 앱의 script.js 파일은 D3 유틸리티 함수를 사용하여 SVG 선 차트를 만들고 페이지에 추가합니다. 여기서 작업 순서가 중요합니다. script.js는 문서가 파싱되고 D3 라이브러리가 로드된 후에 실행되어야 합니다. 따라서 index.html의 닫는 </body> 태그 바로 앞에 포함됩니다.

하지만 D3 스크립트는 페이지의 <head>에 포함되어 나머지 문서의 파싱을 차단합니다.

헤드에 강조표시된 스크립트 태그가 있는 index.html의 스크린샷

두 가지 매직 속성이 스크립트 태그에 추가될 때 파서의 차단을 해제할 수 있습니다.

  • async는 스크립트가 백그라운드에서 다운로드되고 다운로드가 완료된 후 첫 번째 기회에 실행되도록 합니다.

  • defer는 스크립트가 백그라운드에서 다운로드되고 파싱이 완료된 후에 실행되도록 합니다.

이 차트는 전체 페이지에 크게 중요하지 않으며 스크롤해야 볼 수 있는 부분에 위치할 가능성이 높으므로 defer를 사용하여 파서 차단이 없는지 확인합니다.

1단계: defer 속성을 사용하여 스크립트를 비동기식으로 로드

index.html의 17행에서 defer 속성을 <script> 요소에 추가합니다.

<script src="https://d3js.org/d3.v3.min.js" defer></script>

2단계: 연산 순서가 올바른지 확인

이제 D3이 지연되었으므로 D3이 준비되기 전에 script.js이 실행되어 오류가 발생합니다.

defer 속성이 있는 스크립트는 지정된 순서대로 실행됩니다. D3이 준비된 후 script.js가 실행되도록 하려면 defer를 추가하고 문서의 <head> 위로(D3 <script> 요소 바로 뒤) 이동합니다. 이제 더 이상 파서를 차단하지 않으며 다운로드가 더 빨리 시작됩니다.

<script src="https://d3js.org/d3.v3.min.js" defer></script>
<script src="./script.js" defer></script>

서드 파티 리소스 지연 로드

스크롤해야 볼 수 있는 모든 리소스는 지연 로드에 적합합니다.

샘플 앱에 iframe에 삽입된 YouTube 동영상이 있습니다. 페이지에서 전송한 요청 수와 삽입된 YouTube iframe에서 전송된 요청을 확인하려면 다음 단계를 따르세요.

  1. 사이트를 미리 보려면 앱 보기를 누릅니다. 그런 다음 전체 화면 전체 화면입니다.
  2. `Control+Shift+J` (또는 Mac의 경우 `Command+Option+J`)를 눌러 DevTools를 엽니다.
  3. 네트워크 탭을 클릭합니다.
  4. 캐시 사용 중지 체크박스를 선택합니다.
  5. 제한 드롭다운 메뉴에서 빠른 3G를 선택합니다.
  6. 페이지를 새로고침합니다.

DevTools Network 패널의 스크린샷

Network 패널에는 페이지가 총 28건의 요청을 제출했고 약 1MB의 압축된 리소스를 전송한 것으로 표시됩니다.

YouTube iframe에서 보낸 요청을 식별하려면 Initiator 열에서 동영상 ID 6lfaiXM6waw을 찾으세요. 도메인별로 모든 요청을 그룹화하려면 다음 단계를 따르세요.

  • 네트워크 패널에서 열 제목을 마우스 오른쪽 버튼으로 클릭합니다.

  • 드롭다운 메뉴에서 도메인 열을 선택합니다.

  • 도메인별로 요청을 정렬하려면 도메인 열 제목을 클릭합니다.

새로운 정렬을 통해 Google 도메인에 대한 추가 요청이 있음을 알 수 있습니다. YouTube iframe에서는 총 14개의 스크립트, 스타일시트, 이미지 및 글꼴을 요청합니다. 하지만 사용자가 실제로 아래로 스크롤하여 동영상을 재생하지 않는 한 이러한 애셋이 모두 필요하지는 않습니다.

사용자가 페이지의 해당 섹션으로 스크롤할 때까지 동영상을 지연 로드하도록 기다리면 페이지에서 처음 요청하는 횟수를 줄일 수 있습니다. 이 접근 방식은 사용자의 데이터를 초기 로드 속도를 높입니다.

지연 로드를 구현하는 한 가지 방법은 요소가 브라우저의 표시 영역에 들어가거나 나올 때 알려주는 브라우저 API인 Intersection Observer를 사용하는 것입니다.

1단계: 동영상이 처음에 로드되지 않도록 차단하기

동영상 iframe을 지연 로드하려면 먼저 일반적인 방식으로 로드되지 않도록 해야 합니다. src 속성을 data-src 속성으로 대체하여 동영상 URL을 지정하면 됩니다.

<iframe width="560" height="315" data-src="https://www.youtube.com/embed/lS9D6w1GzGY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

data-src는 표준 HTML 요소에 추가 정보를 저장할 수 있도록 하는 데이터 속성입니다. 데이터 속성은 'data-'로 시작하는 한, 아무 이름이나 지정할 수 있습니다.

src가 없는 iframe은 로드되지 않습니다.

2단계: Intersection Observer를 사용하여 동영상 지연 로드하기

사용자가 스크롤할 때 동영상을 로드하려면 그 시점을 알아야 합니다. 바로 Intersection Observer API가 들어가는 곳입니다. Intersection Observer API를 사용하면 추적하려는 요소가 표시 영역에 진입하거나 표시 영역을 벗어날 때마다 실행되는 콜백 함수를 등록할 수 있습니다.

시작하려면 새 파일을 만들고 이름을 lazy-load.js로 지정합니다.

  • 새 파일을 클릭하고 이름을 지정합니다.
  • 이 파일 추가를 클릭합니다.

문서 헤드에 스크립트 태그를 추가합니다.

 <script src="/lazy-load.js" defer></script>

lazy-load.js에서 새 IntersectionObserver를 만들고 실행할 콜백 함수를 전달합니다.

// create a new Intersection Observer
let observer = new IntersectionObserver(callback);

이제 observe 메서드에서 인수로 전달하여 observer에 시청할 타겟 요소 (이 경우 동영상 iframe)를 제공합니다.

// the element that you want to watch
const element = document.querySelector('iframe');

// register the element with the observe method
observer.observe(element);

callbackIntersectionObserverEntry 객체 목록과 IntersectionObserver 객체 자체를 수신합니다. 각 항목에는 항목의 크기, 위치, 표시 영역에 진입한 시간 등을 설명하는 target 요소와 속성이 포함됩니다. IntersectionObserverEntry의 속성 중 하나는 isIntersecting로, 요소가 표시 영역에 진입할 때 true와 같은 불리언 값입니다.

이 예에서 targetiframe입니다. target가 표시 영역에 진입하면 isIntersectingtrue와 같습니다. 실제 동작을 보려면 callback를 다음 함수로 바꿉니다.

let observer = new IntersectionObserver(callback);
let observer = new IntersectionObserver(function(entries, observer) {
    entries.forEach(entry => {
      console.log(entry.target);
      console.log(entry.isIntersecting);
    });
  });
  1. 사이트를 미리 보려면 앱 보기를 누릅니다. 그런 다음 전체 화면 전체 화면입니다.
  2. `Control+Shift+J` (또는 Mac의 경우 `Command+Option+J`)를 눌러 DevTools를 엽니다.
  3. 콘솔 탭을 클릭합니다.

위아래로 스크롤해 보세요. isIntersecting 변경 값과 콘솔에 로깅된 대상 요소가 표시됩니다.

사용자가 해당 위치로 스크롤할 때 동영상을 로드하려면 isIntersecting를 조건으로 사용하여 loadElement 함수를 실행합니다. 이 함수는 iframe 요소의 data-src에서 값을 가져와 iframe 요소의 src 속성으로 설정합니다. 교체하면 동영상 로드가 트리거됩니다. 그런 다음 동영상이 로드되면 observer에서 unobserve 메서드를 호출하여 타겟 요소 감시를 중지합니다.

let observer = new IntersectionObserver(function (entries, observer) {
  entries.forEach(entry => {
    console.log(entry.target);
    console.log(entry.isIntersecting);
  });
});
    if (entry.isIntersecting) {
      // do this when the element enters the viewport
      loadElement(entry.target);
      // stop watching
      observer.unobserve(entry.target);
    }
  });
});

function loadElement(element) {
  const src = element.getAttribute('data-src');
  element.src = src;
}

3단계: 실적 재평가

리소스의 크기와 수가 어떻게 변경되었는지 확인하려면 DevTools Network 패널을 열고 페이지를 다시 새로고침하세요. Network 패널에는 해당 페이지에서 14개의 요청을 보냈고 260KB에 불과한 것으로 표시됩니다. 의미 있는 개선입니다!

이제 페이지를 아래로 스크롤하여 Network 패널을 확인합니다. 동영상으로 이동하면 페이지가 추가 요청을 트리거하는 것을 볼 수 있습니다.

필수 출처 사전 연결

중요하지 않은 JavaScript를 지연하고 YouTube 요청을 지연 로드했으므로 이제 나머지 서드 파티 콘텐츠를 최적화할 차례입니다.

링크에 rel=preconnect 속성을 추가하면 브라우저에 해당 리소스에 대한 요청이 이루어지기 전에 도메인에 대한 연결을 설정하도록 지시합니다. 이 속성은 페이지에 확실하게 필요한 리소스를 제공하는 출처에 가장 적합합니다.

필수 출처에 사전 연결에서 제안된 첫 번째 단계에서 Lighthouse 감사를 실행하여 staticxx.facebook.com 및 youtube.com에 대한 초기 연결을 설정하면 약 400ms를 절약할 수 있습니다.

staticxx.facebook.com 도메인이 강조 표시된 필수 출처 감사에 사전 연결

이제 YouTube 동영상이 지연 로드되므로 소셜 미디어 공유 위젯의 소스인 staticxx.facebook.com만 남습니다. 문서의 <head><link> 태그를 추가하기만 하면 이 도메인에 초기 연결을 설정할 수 있습니다.

  <link rel="preconnect" href="https://staticxx.facebook.com">

실적 재평가

다음은 최적화 후의 페이지 상태입니다. Codelab의 성능 측정 섹션에 나와 있는 단계에 따라 다른 Lighthouse 감사를 실행합니다.

Lighthouse 감사에서 1초의 FCP와 99의 성능 점수를 보여줍니다.