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의 계측을 기반으로 Google은 document.write()를 통해 삽입된 서드 파티 스크립트가 포함된 페이지는 일반적으로 2G의 다른 페이지보다 로드 속도가 2배 느리다는 사실을 확인했습니다.

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

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

이 데이터를 염두에 두고 버전 55부터 Chrome은 모든 사용자를 대신하여 이러한 알려진 악성 패턴을 감지한 경우 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. 스크립트가 동일한 사이트에서 호스팅되지 않았습니다. 즉, Chrome은 일치하는 eTLD+1이 있는 스크립트 (예: www.example.org에 삽입된 js.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월에는 모든 사용자에게 안정화 버전이 제공될 예정입니다.)

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

시간이 지남에 따라 Google에서는 사용자의 연결이 느린 경우 (예: 3G 또는 Wi-Fi 속도가 느릴 때) 개입하려고 합니다. Chrome 상태 항목을 따르세요.

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

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