효율적인 Third-Party Script 로딩

조영도(Young-do Cho)·2020년 2월 21일
2

Third-Party Script

의미

서드파티는 단어 그대로 ‘제3자’를 의미합니다. 그러나 무엇인지 이해하기 위해선 ‘제1자’, ‘제2자’에 대해서도 이해가 필요합니다. 예시로 ‘제1자’, ‘제2자’, 제3자’ 인증을 생각해봅시다.

  1. 제1자 인증은 제품 혹은 서비스를 제공하는 개인 혹은 조직이 요구사항을 모두 충족한다는 보증을 제공하는 것입니다.
  2. 제2자 인증은 해당 개인 혹은 조직이 속한 단체가 보증을 제공하는 것입니다.
  3. 제3자 인증은 완전히 독립적인 제3자가 보증을 제공하는 것입니다.

이 개념을 웹 서비스로 옮겨본다면 다음과 같습니다. 서드파티웹 서비스 제공 단체와 독립적인 단체이고, 이 단체에서 제공하는 스크립트(=JavaScript)라 서드파티 스크립트할 수 있습니다.

서드파티 스크립트의 종류

이러한 스크립트에는 광고, 분석, 위젯 기타 등등 웹을 좀 더 다이내믹하고 인터렉티브하게 만드는 것을 포함합니다. 다음은 서드파티 스크립트의 예입니다.

  1. SNS 공유 버튼 (예: Twitter, Facebook, G+)
  2. 비디오 플레이어 (예: YouTube, Vimeo)
  3. 광고 iframe
  4. 분석 스크립트(Analytics & metrics scripts)
  5. A/B 테스팅 스크립트

아래는 2번의 HTML에서의 예시입니다.

<iframe
  width="560" height="315" src="https://www.youtube.com/embed/mo8thg5XGV0"
  frameborder="0" allow="autoplay; encrypted-media" allowfullscreen>
</iframe>

문제점

서드파티 스크립트는 제공하는 직접 구현하지 않아도 많은 서비스를 추가할 수 있다는 장점이 존재합니다. 하지만, 이는 반대로 해당 기능에 대한 통제를 할 수 없기 때문에, 특정 스크립트에서 성능 저하를 발생시켜도 통제할 수가 없습니다. 다음은 서드파티 스크립트가 발생시킬 수 있는 이슈들의 일부입니다.

  1. 여러 서버에 네트워크 요청을 너무 많이 발생시킬 수 있습니다. 요청이 많아질 수록 로딩이 완료되는 시간은 길어집니다.
  2. 너무 많은 자바스크립트의 실행은 메인 스레드를 지속적으로 바쁘게 많듭니다. 이는 DOM 생성을 막을 수 있어서 페이지 렌더링이 연기될 수 있습니다.
  3. 어떤 서드파티 스크립트가 단일 장애점(SPOF)으로 존재한다면, 로드되는 동안 웹 페이지 전체가 작동하지 않을 수 있습니다.
  4. 캐싱 전략을 세울 수 없어, 스크립트를 필요한 것보다 자주 요청할 수 있습니다.
  5. 스크립트 중 legacy Web API(예: document.write())가 존재할 수 있습니다. 이는 사용자 경험에 악영향을 줄 수 있습니다.

효과적인 로드 방법

서드파티 스크립트를 사용하면서 생길 수 있는 문제점들은 해결할 수 있습니다. 각 방법에 대해서 알아보겠습니다.

1. async 혹은 defer 사용하기

브라우저가 HTML 문서를 파싱(parsing)하면서 DOM을 생성합니다. 그 과정에서 자바스크립트 태그를 만나면 DOM 생성을 중지하고 자바스크립트를 요청한 뒤 로딩이 완료되면 실행합니다. 그러나 해당 태그에 async 혹은 defer을 추가하면 다르게 동작합니다.

  1. async: 이 속성은 DOM을 계속 생성하면서 자바스크립트 파일을 비동기로 요청합니다. 파일 로드가 완료되면, DOM 생성을 중지하고 해당 파일을 실행합니다. 이 속성은 DOM 생성을 최대한 방해하지 않으면서 스크립트를 빠르게 실행시켜야 하는 경우에 사용하면 좋습니다.
  2. defer: 이 속성은 async와 같이 DOM을 계속 생성하면서 자바스크립트 파일을 비동기로 요청합니다. 하지만 DOM 생성이 완료되어야지 해당 파일을 실행합니다. DOM이 생성되고 나서 실행시켜야 하는 스크립트에 사용하면 좋습니다.

2. 미리 연결하기

위는 HTTP 통신 과정입니다. 이처럼 서버에게 자원을 요청하기 위해선 먼저 연결(connection)이 되어야 합니다. 그리고 가장 먼저 서버의 IP 주소를 확인하기 위한 DNS Lookup가 실행되어야 합니다. 그런데 이 DNS Lookup을 미리 수행한다면, 추후 자원을 요청할 때 바로 3-way Handshaking을 시행할 수 있습니다. 이를 가능하게 하는 방법이 <link rel="dns-prefetch">입니다.

<link rel="dns-prefetch" href="http://example.com">

그런데 3-way Handshaking 과정도 미리 수행해서 해당 서버와 계속 연결되어있을 수는 없을까요? 그리고 HTTPS의 경우에는 IP 주소를 알아도 SSL을 통한 인증도 진행하기 때문에 연결 수립이 좀 더 오래 걸릴 수 있습니다. 그러나 <link rel="preconnect">를 사용한다면 해당 서버와 미리 연결할 수 있습니다.

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

그러나 위 방법은 연결 수립 후 10초 이내 해당 서버에게 요청할 자원이 없다면 자동으로 끊어집니다. 그래서 10초 이내 사용될 자원에 대해서 이 방법을 활용하는 것을 권장합니다.

그리고 preconnect방식은 dns-prefetch방식보다 좁은 브라우저 지원범위를 가지고 있습니다. 이 점을 착안하여 dns-prefetch방식을 preconnect방식의 아래와 같이 fallback으로 사용하는 것을 추천합니다.

<link rel="preconnect" href="http://example.com">
<link rel="dns-prefetch" href="http://example.com">

3. 자신이 제공하기(=Self-hosting)

서드파티 스크립트들을 자신의 서버에서 제공하는 것은 여러 이점을 가질 수 있습니다. 기존에는 여러 서버와 연결했었다면, 자신의 서버에서 제공함으로서 연결 수립을 최소화할 수 있습니다. 또한 자신이 원하는 캐싱 전략을 수립할 수도 있고, HTTP2와 같은 더 빠른 속도의 통신 프로토콜을 사용할 수도 있습니다.

이 방식의 단점은 해당 스크립트에 대한 업데이트를 지속적으로 확인해야한다는 것입니다. 그렇지 않으면 오래된 스크립트를 제공할 수 있습니다. 이는 해당 스크립트에 보안 취약점이 발견되어서 업데이트가 되더라도 이를 확인하지 않는다면 보안 취약점을 자신의 웹 서비스에 그대로 유지하는 결과를 초래하게 됩니다.

그러나 스크립트에 대한 업데이트를 자주 확인할 수 있다면, 중요한 역할을 가진 서드파티 스크립트는 자신이 제공하는 것이 유리할 수 있습니다.

4. 필요할 때 요청하기(=Lazy-Loading)

웹 서비스의 규모가 커질 수록 요청해야하는 자원의 총량도 커질 수 밖에 없습니다. 이는 아무리 최적화를 진행해도 로딩이 완료되는 시간이 길어지는 것을 막을 수 없다는 것을 의미합니다. 이를 해결하기 위해 사용자가 당장 필요하지 않는 스크립트에 대한 로딩을 뒤로 늦추는 방법을 사용할 수 있습니다. 예를 들어, 아직 화면에 나타나지 않은 광고 이미지를 화면에서 보이면 그 때 요청하는 것입니다.

Lazy-Loading을 사용할 수 있는 방법은 여러가지가 존재합니다. 예를 들어, Intersection Observer 는 브라우저 API로 사용자가 보고 있는 화면을 효율적으로 감지할 수 있습니다. 그리고 LazySizes는 이미지와 iframes에 Lazy-loading을 적용할 수 있는 유명한 자바스크립트 라이브러리입니다.

결론

서드파티 스크립트를 사용하면 웹 페이지를 좀 더 풍부하게 만들 수 있습니다. 그러나 사용하는 것도 중요하지만 사용하기 위해 로딩하는 과정을 최적화하는 것 역시 중요합니다. 현재 서드파티 스크립트를 사용한다면 이 링크를 통해 현재의 문제점을 확인하는 것을 추천합니다.

참고

profile
개념 정리 + 호기심 해결용 블로그

0개의 댓글