document.write()에 대한 개입

최근 Chrome의 개발자 콘솔에서 다음과 같은 경고를 보고 어떤 경고인지 궁금했던 적이 있나요?

(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의 다른 페이지보다 로드 속도가 2배 느립니다.

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

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

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

  1. 사용자의 연결이 느린 경우, 특히 2G를 사용하는 경우 (향후에는 느린 3G 또는 느린 Wi-Fi와 같이 느린 연결을 사용하는 다른 사용자에게 변경사항이 적용될 수 있습니다.)
  2. document.write()는 최상위 문서에 있습니다. iframe 내의 document.write 스크립트는 기본 페이지 렌더링을 차단하지 않으므로 개입이 적용되지 않습니다.
  3. document.write()의 스크립트는 파서를 차단합니다. 'async' 또는 'defer' 속성이 있는 스크립트는 계속 실행됩니다.
  4. 스크립트가 동일한 사이트에서 호스팅되지 않았습니다. 즉, 일치하는 eTLD+1이 있는 스크립트 (예: www.example.org에 삽입된 js.example.org에서 호스팅되는 스크립트)에 Chrome이 개입하지 않습니다.
  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부터 Play Console에 경고만 표시하는 것으로 시작했습니다. (베타 버전은 2016년 7월, 2016년 9월부터 모든 사용자가 안정화 버전을 사용할 수 있을 것으로 예상됩니다.)

Google은 2016년 10월 중순에 모든 사용자에게 안정화 버전으로 출시될 것으로 예상되는 Chrome 54부터 잠정적으로 2G 사용자를 대상으로 삽입된 스크립트를 차단하기 위해 개입할 예정입니다. 더 많은 업데이트는 Chrome 상태 항목을 확인하세요.

시간이 지남에 따라 사용자의 연결 속도가 느린 경우 (예: 3G 또는 Wi-Fi 속도가 느린 경우) 조치를 취할 계획입니다. 이 Chrome 상태 항목을 팔로우하세요.

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

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