Una nueva API de JavaScript que puede ayudarte a evitar el equilibrio entre el rendimiento de carga y la capacidad de respuesta de la entrada.
Cargarlo rápido es difícil. Sitios que aprovechan JS para procesar su contenido actualmente entre el rendimiento de carga y las entradas capacidad de respuesta: se debe realizar todo el trabajo necesario para la de una sola vez (mejor rendimiento de carga, peor capacidad de respuesta a la entrada) o dividir el trabajo en tareas más pequeñas para que sea adaptable entrada y pintura (peor rendimiento de carga, mejor entrada la capacidad de respuesta).
Para eliminar la necesidad de hacer esta compensación, Facebook propuso e implementó
la API de isInputPending()
en Chromium para mejorar la capacidad de respuesta sin
rindiendo. Según los comentarios que recibimos sobre la prueba de origen, aplicamos una serie de actualizaciones al
API y nos complace anunciar que la API ahora se envía de forma predeterminada en Chromium
¡87!
Compatibilidad del navegador
isInputPending()
se envió en navegadores basados en Chromium a partir de la versión 87.
Ningún otro navegador indicó la intención de enviar la API.
Información general
La mayor parte del trabajo en el ecosistema JS actual se realiza en un solo subproceso: el principal. Esto proporciona un modelo de ejecución sólido a los desarrolladores, pero la experiencia del usuario (la capacidad de respuesta en particular) puede verse afectada drásticamente si la secuencia de comandos se ejecuta durante un período prolongado tiempo. Si la página hace mucho trabajo mientras se activa un evento de entrada, Por ejemplo, la página no controlará el evento de entrada de clic hasta que de datos completados.
En la actualidad, la práctica recomendada es abordar este problema rompiendo los JavaScript en bloques más pequeños. Mientras se carga la página, esta puede ejecutar una un poco de JavaScript, y luego ceder y pasar el control al navegador. El el navegador puede comprobar la cola de eventos de entrada y ver si tiene que informar a la página. Luego, el navegador puede volver a ejecutar Se bloquea JavaScript a medida que se agregan. Esto es útil, pero puede causar otros problemas.
Cada vez que la página le devuelve el control al navegador, se necesita un tiempo para el navegador para comprobar la cola de eventos de entrada, procesar eventos y retomar Bloque de JavaScript. Si bien el navegador responde a los eventos más rápido, el el tiempo de carga de la página se ralentiza. Y si cederemos con demasiada frecuencia, la página se carga demasiado lento. Si rindemos menos seguido, el navegador tardará más en a los eventos de los usuarios y las personas se frustran. No es divertido.
En Facebook, queríamos saber cómo sería el panorama
un nuevo enfoque de carga que eliminaría esta frustrante compensación. Mié
se comunicó con nuestros amigos de Chrome sobre esto y idearon la propuesta
para isInputPending()
. La API de isInputPending()
es la primera en usar el concepto de
interrumpe las entradas del usuario en la Web y permite que se ejecute
pueda comprobar la entrada sin ceder al navegador.
Como había interés en la API, nos asociamos con nuestros colegas en Chrome. para implementar y enviar la función en Chromium. Con ayuda de Chrome ingenieros, logramos que los parches se implementaran tras una prueba de origen. (que permite que Chrome pruebe los cambios y obtenga comentarios de los desarrolladores antes de lanzar una API por completo).
Hemos tomado comentarios de la prueba de origen y de los demás miembros del W3C Web Performance Working Group e implementamos cambios en la API.
Ejemplo: un programador más productivo
Supongamos que debes realizar
una gran cantidad de trabajo de bloqueo de visualización
como generar lenguaje de marcado a partir de componentes, excluir números primos o
dibujando un ícono giratorio de carga. Cada uno de ellos se divide en una tabla
un elemento de trabajo. Con el patrón del programador, esbozamos cómo podríamos procesar
nuestro trabajo en una función processWorkQueue()
hipotética:
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();
}
Si invocamos processWorkQueue()
más adelante en una macrotarea nueva a través de setTimeout()
,
al navegador la capacidad de responder a la entrada (puede,
ejecutar controladores de eventos antes de que se reanude el trabajo) y, al mismo tiempo, administrar la ejecución de
sin interrupciones. Sin embargo, es posible que otros trabajos
nos desprogramen por mucho tiempo
que requiera el control del bucle de eventos o que obtenga hasta QUANTUM
milisegundos adicionales
de latencia de eventos.
Esto está bien, pero ¿podemos hacerlo mejor? ¡Por supuesto!
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();
}
Mediante la introducción de una llamada a navigator.scheduling.isInputPending()
, podemos hacer lo siguiente:
responden a las entradas más rápido y nos aseguramos
de que el bloqueo de la pantalla funcione
se ejecuta sin interrupciones. Si no nos interesa manejar algo
aparte de las aportaciones (p.ej., pintura) hasta que el trabajo esté completo, podemos aumentar
la longitud de QUANTUM
.
De forma predeterminada, “continuo” no se muestran desde isInputPending()
. Estos
incluyen a mousemove
, pointermove
y otros. Si te interesa rendir por
también, no hay problema. Cuando proporcionas un objeto a isInputPending()
con
Se estableció includeContinuous
en true
, así que todo listo:
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();
}
Eso es todo. Los frameworks como React están agregando compatibilidad con isInputPending()
en su
las bibliotecas de programación principales
con una lógica similar. Con suerte, esto te permitirá
desarrolladores que usan estos frameworks para beneficiarse de isInputPending()
detrás de escena
sin reescrituras significativas.
Rindar no siempre es malo
Cabe destacar que rendir menos no es la solución adecuada para todos los usos. para determinar si este es el caso. Existen muchos motivos para devolver el control al navegador además de procesar eventos de entrada, como realizar la renderización y ejecutar otras secuencias de comandos en la página.
Existen casos en los que el navegador no puede asignar correctamente el atributo pendiente
de entrada. En particular, configurar clips y máscaras complejas para origen cruzado
Los iframes pueden informar falsos negativos (p.ej., isInputPending()
puede mostrarse de forma inesperada
false cuando se orienta a estos marcos). Asegúrate de rendir con suficiente frecuencia si
tu sitio requiere interacciones con submarcos estilizados.
Además, ten en cuenta otras páginas que comparten un bucle de eventos. En plataformas como
como Chrome para Android, es bastante común que varios orígenes compartan un evento
bucle. isInputPending()
nunca mostrará true
si la entrada se envía a un
marco de origen cruzado y, por lo tanto, las páginas en segundo plano pueden interferir con el
la capacidad de respuesta de las páginas en primer plano. Es posible que quieras reducir, posponer o ceder
con más frecuencia cuando se realizan trabajos en segundo plano con la API de visibilidad de páginas.
Te recomendamos usar isInputPending()
con discreción. Si no hay
para bloquear a los usuarios y, luego, sé amable con los demás en el bucle de eventos.
rinde con más frecuencia. Las tareas largas pueden ser dañinas.
Comentarios
- Puedes dejar comentarios sobre la especificación en el is-input-pending.
- Comunícate con @acomminos (uno de los autores de las especificaciones). en Twitter.
Conclusión
Nos complace que se lance isInputPending()
y que los desarrolladores puedan
para comenzar a usarlo hoy mismo. Esta API es la primera vez que Facebook compila una
nueva API web y la llevó de la incubación de ideas a la propuesta de estándares,
el envío en un navegador. Queremos agradecer a todas las personas que nos ayudaron a lograrlo
y mencionar a todos los usuarios de Chrome que nos ayudaron a desarrollar
esta idea y repartirla.
Foto hero de Will H McMahan en Retiro: