isInputPending()을 사용한 JS 예약 개선

로드 성능과 입력 응답성 간의 균형을 피하는 데 도움이 될 수 있는 새로운 JavaScript API입니다.

Nate Schloss
Nate Schloss
Andrew Comminos
Andrew Comminos

빠르게 로드하는 것은 어렵습니다. 현재 JS를 활용하여 콘텐츠를 렌더링하는 사이트 로드 성능과 입력 사이에서 절충해야 함 응답성: 디스플레이에 필요한 모든 작업을 실행하거나 동시에 모두 수행 (로드 성능 향상, 입력 응답성 저하) 작업에 대한 응답성을 유지하기 위해 작업을 더 작은 태스크로 분할 입력 및 페인트 (부하 성능이 저하되고, 입력 성능이 향상됨) 응답성).

Facebook은 이러한 트레이드오프를 할 필요성을 없애기 위해 Chromium의 isInputPending() API를 호출하여 양보하는 거죠. 오리진 트라이얼 의견을 바탕으로, 이제 이 API가 Chromium에 기본적으로 탑재됩니다 87입니다.

브라우저 호환성

브라우저 지원

  • Chrome: 87 <ph type="x-smartling-placeholder">
  • Edge: 87. <ph type="x-smartling-placeholder">
  • Firefox: 지원되지 않음 <ph type="x-smartling-placeholder">
  • Safari: 지원되지 않음 <ph type="x-smartling-placeholder">

소스

isInputPending()는 버전 87부터 Chromium 기반 브라우저에서 제공됩니다. 다른 어떤 브라우저에서도 API 전송 의도를 감지하지 못했습니다.

배경

오늘날의 JS 생태계에서 대부분의 작업은 단일 스레드, 즉 기본 스레드에서 실행됩니다. 이는 개발자에게 강력한 실행 모델을 제공하지만, 스크립트를 장시간 실행하면 (특히 응답성) 속도가 크게 저하될 수 있습니다. 있습니다. 입력 이벤트가 실행되는 동안 페이지가 많은 작업을 하는 경우 예를 들어 이 작업이 끝날 때까지 페이지에서 클릭 입력 이벤트를 처리하지 않습니다. 나타냅니다.

현재 가장 좋은 방법은 JavaScript를 더 작은 블록으로 만듭니다. 페이지가 로드되는 동안 페이지가 그런 다음 제어권을 양보하여 브라우저에 다시 전달합니다. 이 브라우저는 입력 이벤트 큐를 확인하고 페이지에 알려야 합니다 그러면 브라우저에서 JavaScript 블록이 추가될 때 차단됩니다. 이렇게 하면 도움이 되지만 다른 문제가 발생할 수 있습니다.

페이지가 브라우저에 다시 제어권을 양도할 때마다 브라우저에서 입력 이벤트 대기열을 확인하고, 이벤트를 처리하고, JavaScript 블록. 브라우저는 이벤트에 더 빠르게 반응하지만 속도가 느려집니다 페이지를 너무 자주 출력하면 로드 속도가 너무 느립니다. 결과가 더 적으면 브라우저에서 사람들은 좌절감을 느낍니다. 재미없어요.

긴 JS 작업을 실행하면 브라우저에서 이벤트를 전달할 시간이 적음을 보여주는 다이어그램

Facebook에서는 새로운 로드 방식을 도입했습니다. Chrome 동료들에게 이에 대해 얘기해서 (isInputPending()) isInputPending() API는 웹상의 사용자 입력에 인터럽트를 주고 JavaScript가 브라우저에 양보하지 않고 입력을 확인할 수 있습니다.

isInputPending()을 사용하면 JS가 브라우저에 완전히 다시 실행하지 않고 대기 중인 사용자 입력이 있는지 확인할 수 있음을 보여주는 다이어그램.

API에 관심이 많아서 Chrome의 동료들과 협력했습니다. Chromium에서 기능을 구현하고 제공합니다. Chrome 활용 패치는 오리진 트라이얼을 거쳐 착륙했습니다. (Chrome에서 변경사항을 테스트하고 개발자로부터 피드백을 받을 수 있는 방법임) API를 완전히 출시하기 전).

이제 오리진 트라이얼과 다른 참가자들로부터 피드백을 받았습니다. W3C 웹 성능 실무 그룹에 참여하고 API에 변경사항을 구현했습니다.

예: 수익률 스케줄러

모바일 장치를 로드하기 위해 많은 디스플레이 차단 작업이 예를 들어 구성 요소에서 마크업 생성, 프라임 제거, 멋진 로딩 스피너를 그리고 있습니다. 이들은 각각 독립되어 있으며 작업 항목을 찾습니다. 스케줄러 패턴을 사용하여 인코더-디코더 아키텍처를 가상의 processWorkQueue() 함수에서 수행한 작업:

const DEADLINE = performance.now() + QUANTUM;
while (workQueue.length > 0) {
  if (performance.now() >= DEADLINE) {
    // Yield the event loop if we're out of time.
    setTimeout(processWorkQueue);
    return;
  }
  let job = workQueue.shift();
  job.execute();
}

나중에 setTimeout()를 통해 새로운 매크로 태스크에서 processWorkQueue()를 호출하면 브라우저가 입력에 어느 정도 반응할 수 있게 해 줍니다. 작업이 재개되기 전에 이벤트 핸들러 실행)을 유지하면서 비교적 즐길 수 있습니다. 하지만 다른 업무로 인해 오랫동안 일정이 변경될 수도 있습니다. 이벤트 루프를 제어하거나 최대 QUANTUM밀리초를 추가 이벤트 지연 시간을 단축할 수 있습니다

괜찮지만 더 개선할 수 있을까요? 물론입니다.

const DEADLINE = performance.now() + QUANTUM;
while (workQueue.length > 0) {
  if (navigator.scheduling.isInputPending() || performance.now() >= DEADLINE) {
    // Yield if we have to handle an input event, or we're out of time.
    setTimeout(processWorkQueue);
    return;
  }
  let job = workQueue.shift();
  job.execute();
}

navigator.scheduling.isInputPending() 호출을 도입하면 다음을 실행할 수 있습니다. 입력에 더 빠르게 반응하면서 디스플레이 차단 작업도 그 외에는 중단 없이 실행됩니다 이러한 문제를 처리하는 데 작업이 완료될 때까지 입력 이외의 다른 작업 (예: 그림 그리기)을 QUANTUM의 길이도 마찬가지입니다.

기본적으로 '연속' 이벤트는 isInputPending()에서 반환되지 않습니다. 이러한 mousemove, pointermove 등이 포함됩니다. 당신이 얻고자 하는 것에 대해 이것들도 괜찮습니다. 다음을 사용하여 isInputPending()에 객체 제공 includeContinuous이(가) true(으)로 설정되었습니다. 이제 시작할 수 있습니다.

const DEADLINE = performance.now() + QUANTUM;
const options = { includeContinuous: true };
while (workQueue.length > 0) {
  if (navigator.scheduling.isInputPending(options) || performance.now() >= DEADLINE) {
    // Yield if we have to handle an input event (any of them!), or we're out of time.
    setTimeout(processWorkQueue);
    return;
  }
  let job = workQueue.shift();
  job.execute();
}

작업이 끝났습니다. React와 같은 프레임워크는 자체 프로세스에 isInputPending() 지원을 구축합니다. 핵심 예약 라이브러리를 사용합니다. 이렇게 하면 isInputPending()의 이점을 누리기 위해 이러한 프레임워크를 사용하는 개발자 개발 비용을 절감할 수 있습니다

수익률이 항상 나쁘지는 않음

적은 양의 수익을 창출하는 것이 모든 사용 사례에 적합한 솔루션은 아니라는 점에 주목해야 합니다. 있습니다. 제어 기능을 브라우저에 반환하는 것 외에 다른 여러 가지 이유가 있습니다. 다른 스크립트 실행과 같은 입력 이벤트를 처리하여 있습니다.

브라우저에서 보류 중 상태를 제대로 파악하지 못하는 경우가 있습니다. 사용됩니다. 특히 교차 출처에 대해 복잡한 클립과 마스크를 설정하는 경우 iframe에서 거짓음성을 보고할 수 있습니다 (예: isInputPending()가 예기치 않게 반환될 수 있음). false로 설정됩니다. 에코가 필요한 경우 충분히 양보하고 사이트에 양식화된 하위 프레임과의 상호작용이 필요하지 않습니다.

이벤트 루프를 공유하는 다른 페이지도 주의하세요. 플랫폼에서 Android용 Chrome과 마찬가지로 여러 출처에서 하나의 이벤트를 합니다. 입력이 다음으로 전달된 경우 isInputPending()true를 반환하지 않습니다. 충돌하므로 배경 페이지는 포그라운드 페이지의 응답성을 향상할 수 있습니다. 수익을 줄이거나, 연기하거나, 수익을 창출하고 싶을 수 있습니다 Page Visibility API를 사용하여 백그라운드에서 작업할 때 더 자주 할 수 있습니다.

isInputPending()을(를) 신중하게 사용하실 것을 권장합니다. 사용자가 이벤트 루프에서 다른 사용자를 친절하게 대하는 방식으로 더 자주 생성됩니다 장기 작업은 유해할 수 있습니다.

의견

  • 다음에서 사양에 대한 의견을 남겨 주세요. is-input-pending 저장소가 포함됩니다.
  • @acomminos (사양 작성자 중 한 명)에게 문의하세요. 을 참고하세요.

결론

isInputPending()이 출시되어 개발자들이 지금 바로 사용해 보세요. 이 API는 Facebook에서 새로운 웹 API를 개발했고 아이디어 구상 단계에서 표준 제안 단계까지 포함되어 있습니다. 여기까지 도움을 주신 모든 분들께 감사드립니다. 이 자리를 빌려 더 나은 서비스를 제공할 수 있도록 도움을 준 Chrome의 모든 분께 배송받으세요

윌 H 맥마한의 히어로 사진 스플래시 해제.