document.write()에 대한 개입

최근 Chrome의 Play Console에 다음과 같은 경고가 표시되어 그 의미를 궁금해하셨나요?

(index):34 A Parser-blocking, cross-origin script,
https://paul.kinlan.me/ad-inject.js, is invoked via document.write().
This may be blocked by the browser if the device has poor network connectivity.

구성 가능성은 웹의 강력한 기능 중 하나로, 서드 파티에서 빌드한 서비스와 쉽게 통합하여 멋진 새 제품을 만들 수 있습니다. 구성 가능성의 단점 중 하나는 사용자 환경에 대한 책임 공유를 의미한다는 점입니다. 통합이 최적화되지 않으면 사용자 환경에 부정적인 영향을 미칩니다.

성능 저하의 한 가지 원인은 페이지 내에서 document.write()를 사용하는 것, 특히 스크립트를 삽입하는 용도로 사용하는 것입니다. 다음은 무해해 보이지만 사용자에게 실제 문제가 될 수 있습니다.

document.write('<script src="https://example.com/ad-inject.js"></script>');

브라우저가 페이지를 렌더링하려면 먼저 HTML 마크업을 파싱하여 DOM 트리를 빌드해야 합니다. 파서가 스크립트를 만날 때마다 HTML 파싱을 계속하기 전에 스크립트를 중지하고 실행해야 합니다. 스크립트가 다른 스크립트를 동적으로 삽입하면 파서는 리소스가 다운로드될 때까지 더 오래 기다려야 하므로 하나 이상의 네트워크 왕복이 발생하고 페이지의 첫 번째 렌더링 시간이 지연될 수 있습니다.

2G와 같이 속도가 느린 인터넷 사용자의 경우 document.write()를 통해 동적으로 삽입된 외부 스크립트로 인해 기본 페이지 콘텐츠 표시가 수십 초 동안 지연되거나 페이지가 로드되지 않거나 로드하는 데 시간이 너무 오래 걸려 사용자가 포기할 수 있습니다. Chrome의 계측을 기반으로 document.write()를 통해 삽입된 서드 파티 스크립트가 포함된 페이지는 2G에서 다른 페이지보다 일반적으로 로드 속도가 두 배 느린 것으로 확인되었습니다.

2G 연결 사용자로 제한된 Chrome 안정화 버전 사용자의 1% 를 대상으로 28일간의 필드 실험을 통해 데이터를 수집했습니다. 2G에서의 모든 페이지 로드 중 7.6% 에는 최상위 문서에서 document.write()를 통해 삽입된 교차 사이트 파서 차단 스크립트가 하나 이상 포함되어 있었습니다. 이러한 스크립트의 로드를 차단한 결과 로드가 다음과 같이 개선되었습니다.

  • 콘텐츠가 포함된 첫 페인트(페이지가 효과적으로 로드되고 있음을 사용자에게 시각적으로 확인해 주는 기능)에 도달하는 페이지 로드가 10% 증가하고, 완전히 파싱된 상태에 도달하는 페이지 로드가 25% 증가했으며, 새로고침 횟수가 10% 감소하여 사용자 불만이 줄었음을 알 수 있습니다.
  • 콘텐츠가 포함된 첫 페인트까지의 평균 시간이 21% 감소했습니다 (1초 이상 빨라짐).
  • 페이지 파싱에 걸리는 평균 시간이 38% 감소하여 거의 6초가 개선되었으며, 사용자에게 중요한 정보를 표시하는 데 걸리는 시간이 크게 단축되었습니다.

이러한 데이터를 고려하여 Chrome은 버전 55부터 Chrome에서 document.write()가 처리되는 방식을 변경하여 이러한 잘 알려진 잘못된 패턴을 감지하면 모든 사용자를 대신하여 개입합니다 (Chrome 상태 참고). 특히 Chrome은 다음 조건을 모두 충족하는 경우 document.write()를 통해 삽입된 <script> 요소를 실행하지 않습니다.

  1. 사용자가 느린 연결을 사용하고 있습니다(특히 2G를 사용하는 경우). 향후 느린 3G 또는 느린 Wi-Fi와 같이 느린 연결을 사용하는 다른 사용자에게도 이 변경사항이 적용될 수 있습니다.
  2. document.write()가 최상위 문서에 있습니다. iframe 내의 document.written 스크립트는 기본 페이지 렌더링을 차단하지 않으므로 개입이 적용되지 않습니다.
  3. document.write()의 스크립트는 파서를 차단합니다. 'async' 또는 'defer' 속성이 있는 스크립트는 계속 실행됩니다.
  4. 스크립트가 동일한 사이트에 호스팅되지 않습니다. 즉, Chrome은 일치하는 eTLD+1이 있는 스크립트 (예: js.example.org에 호스팅된 스크립트가 www.example.org에 삽입됨)에는 개입하지 않습니다.
  5. 스크립트가 아직 브라우저 HTTP 캐시에 없습니다. 캐시의 스크립트는 네트워크 지연이 발생하지 않으며 계속 실행됩니다.
  6. 페이지 요청이 새로고침이 아닙니다. 사용자가 새로고침을 트리거한 경우 Chrome은 개입하지 않고 페이지를 정상적으로 실행합니다.

서드 파티 스니펫은 document.write()를 사용하여 스크립트를 로드하는 경우가 있습니다. 다행히 대부분의 서드 파티는 페이지의 나머지 콘텐츠 표시를 차단하지 않고 서드 파티 스크립트를 로드할 수 있는 비동기 로드 대안을 제공합니다.

이 문제를 해결하려면 어떻게 해야 하나요?

간단한 답변은 document.write()를 사용하여 스크립트를 삽입하지 않는 것입니다. Google에서는 비동기 로더 지원을 위한 알려진 서비스를 유지 관리하고 있으므로 계속해서 확인하는 것이 좋습니다.

목록에 없는 제공업체가 비동기 스크립트 로드를 지원하는 경우 모든 사용자에게 도움이 되도록 Google에 알려주시면 페이지를 업데이트하겠습니다.

제공업체에서 페이지에 스크립트를 비동기식으로 로드하는 기능을 지원하지 않는 경우 제공업체에 문의하여 Google과 제공업체에 영향을 미치는 방식을 알리세요.

제공업체에서 document.write()가 포함된 스니펫을 제공하는 경우 스크립트 요소에 async 속성을 추가하거나 document.appendChild() 또는 parentNode.insertBefore()와 같은 DOM API를 사용하여 스크립트 요소를 추가할 수 있습니다.

사이트에 영향을 미치는 시점을 감지하는 방법

제한이 적용되는지 여부를 결정하는 기준이 많으므로 영향을 받는지 어떻게 알 수 있나요?

사용자가 2G를 사용하는 경우 감지

이 변경사항이 미칠 수 있는 잠재적 영향을 파악하려면 먼저 2G를 사용하는 사용자 수를 파악해야 합니다. Chrome에서 제공되는 Network Information API를 사용하여 사용자의 현재 네트워크 유형과 속도를 감지한 다음 분석 또는 실제 사용자 측정항목(RUM) 시스템에 헤드업을 전송할 수 있습니다.

if(navigator.connection &&
    navigator.connection.type === 'cellular' &&
    navigator.connection.downlinkMax <= 0.115) {
    // Notify your service to indicate that you might be affected by this restriction.
}

Chrome DevTools에서 경고 포착

Chrome 53부터 DevTools는 문제가 있는 document.write() 문장에 경고를 표시합니다. 특히 document.write() 요청이 기준 2~5를 충족하는 경우(Chrome은 이 경고를 보낼 때 연결 기준을 무시함) 경고는 다음과 같이 표시됩니다.

문서 쓰기 경고

Chrome DevTools에서 경고를 확인하는 것은 좋지만 대규모로 이를 감지하려면 어떻게 해야 하나요? 개입이 발생할 때 서버로 전송되는 HTTP 헤더를 확인할 수 있습니다.

스크립트 리소스의 HTTP 헤더 확인

document.write를 통해 삽입된 스크립트가 차단되면 Chrome은 요청된 리소스에 다음 헤더를 전송합니다.

Intervention: <https://shorturl/relevant/spec>;

document.write를 통해 삽입된 스크립트가 발견되고 다양한 상황에서 차단될 수 있는 경우 Chrome은 다음을 전송할 수 있습니다.

Intervention: <https://shorturl/relevant/spec>; level="warning"

개입 헤더는 스크립트의 GET 요청의 일부로 전송됩니다(실제 개입의 경우 비동기식으로).

미래에는 어떤 일이 일어날까?

초기 계획은 기준이 충족될 때 이 개입을 실행하는 것입니다. Chrome 53에서는 개발자 콘솔에 경고만 표시하기 시작했습니다. (베타는 2016년 7월에 출시되었습니다. 2016년 9월에는 모든 사용자가 안정화 버전을 사용할 수 있을 것으로 예상됩니다.)

2016년 10월 중순에 모든 사용자를 대상으로 안정화 버전이 출시될 것으로 예상되는 Chrome 54부터는 일단 2G 사용자를 대상으로 삽입된 스크립트를 차단하기 위한 조치를 취할 예정입니다. 자세한 내용은 Chrome 상태 항목을 참고하세요.

앞으로는 사용자의 연결이 느린 경우 (예: 느린 3G 또는 Wi-Fi) 개입할 계획입니다. 이 Chrome 상태 항목을 따르세요.

자세한 내용이 궁금하신가요?

자세한 내용은 다음 추가 리소스를 참고하세요.