Una nuova API JavaScript che può aiutarti a evitare l'equilibrio tra prestazioni di carico e reattività dell'input.
Caricare i video velocemente è difficile. Attualmente i siti che utilizzano JS per eseguire il rendering dei propri contenuti dover trovare un compromesso tra le prestazioni di carico e l'input reattività: eseguire tutto il lavoro necessario per la tutti contemporaneamente (prestazioni di caricamento migliori, minore reattività dell'input) oppure suddividere il lavoro in attività più piccole per garantire la reattività input e colorazione (prestazioni peggiori di caricamento, input migliori reattività).
Per eliminare la necessità di scendere a compromessi, Facebook ha proposto e implementato
l'API isInputPending()
in Chromium per migliorare la reattività senza
cedere. In base al feedback sulla prova dell'origine, abbiamo apportato una serie di aggiornamenti
e siamo lieti di annunciare che ora l'API viene spedita per impostazione predefinita in Chromium
87!
Compatibilità del browser
isInputPending()
è disponibile nei browser basati su Chromium a partire dalla versione 87.
Nessun altro browser ha segnalato l'intenzione di distribuire l'API.
Sfondo
La maggior parte del lavoro nell'ecosistema JS di oggi viene svolta in un unico thread: il thread principale. Questo fornisce agli sviluppatori un solido modello di esecuzione, ma l'esperienza utente (in particolare la reattività) può risentirne drasticamente se lo script viene eseguito nel tempo. Se la pagina sta svolgendo molto lavoro mentre viene attivato un evento di input, Ad esempio, la pagina non gestirà l'evento di input del clic fino a quando vengono completate.
La best practice attuale consiste nell'affrontare questo problema interrompendo il di JavaScript in blocchi più piccoli. Durante il caricamento della pagina, è possibile eseguire un un po' di JavaScript per poi cedere e ritrasmettere il controllo al browser. La browser può quindi controllare la coda degli eventi di input e vedere se c'è qualcosa deve indicare alla pagina. Poi il browser può tornare a eseguire Blocchi JavaScript man mano che vengono aggiunti. Questa operazione aiuta, ma può causare altri problemi.
Ogni volta che la pagina restituisce il controllo al browser, occorre un po' di tempo per il browser per controllare la coda degli eventi di input, elaborare gli eventi e scegliere di blocco JavaScript. Mentre il browser risponde agli eventi più rapidamente, nel complesso il tempo di caricamento della pagina rallenta. E se diamo troppo spesso, la pagina si carica troppo lentamente. Se la resa avviene meno spesso, occorre più tempo prima che il browser rispondono agli eventi degli utenti e le persone si sentono frustrate. Non è divertente.
Noi di Facebook volevamo vedere come sarebbero le cose
se trovassimo un
un nuovo approccio al caricamento che eliminerebbe questo frustrante compromesso. Me
abbiamo contattato i nostri amici di Chrome e abbiamo proposto
per isInputPending()
. L'API isInputPending()
è la prima a utilizzare il concetto di
interrompe gli input dell'utente sul web e consente il riconoscimento
in grado di controllare l'input senza cedere al browser.
Dato l'interesse dimostrato per l'API, abbiamo collaborato con i nostri colleghi di Chrome per implementare e distribuire la funzionalità in Chromium. Con l'aiuto di Chrome ingegneri, abbiamo riscontrato una prova dell'origine (che consente a Chrome di testare le modifiche e ricevere feedback dagli sviluppatori prima del rilascio completo di un'API).
Abbiamo preso feedback dalla prova dell'origine e dagli altri membri del W3C Web Performance Working Group e ha implementato modifiche all'API.
Esempio: scheduler più redditizio
Supponiamo di dover svolgere del lavoro per bloccare il display
pagina, ad esempio generazione del markup dai componenti, esclusione dei numeri primi
disegnando semplicemente
una rotellina di caricamento. Ognuna di queste è suddivisa in una
dell'elemento di lavoro. Usando il pattern dello scheduler, vediamo come potremmo elaborare
il nostro lavoro in un'ipotetica funzione 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();
}
Richiamando processWorkQueue()
in un secondo momento in una nuova macro attività tramite setTimeout()
,
il browser ha la possibilità di rispondere in qualche modo all'input (può
i gestori di eventi prima della ripresa del lavoro) rimanendo in grado di eseguire relativamente
senza interruzioni. Però potremmo essere riprogrammati a lungo da altri lavori
che vuole controllare il loop di eventi, oppure ottenere fino a QUANTUM
millisecondi in più
di latenza degli eventi.
Questo va bene, ma possiamo fare di meglio? Assolutamente sì!
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();
}
Introducendo una chiamata a navigator.scheduling.isInputPending()
, possiamo
rispondere agli input più velocemente garantendo al contempo che il nostro sistema di blocco
viene eseguita senza interruzioni. Se non ci interessa gestire
a parte l'input (ad es. dipingere) fino a quando il lavoro non è completo, possiamo aumentare
anche la lunghezza di QUANTUM
.
Per impostazione predefinita, "continua" eventi non vengono restituiti da isInputPending()
. Questi
includono mousemove
, pointermove
e altri. Se ti interessa cedere
anche queste, nessun problema. Fornendo un oggetto a isInputPending()
con
includeContinuous
impostato su true
, è tutto pronto:
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();
}
È tutto. I framework come React stanno integrando il supporto di isInputPending()
nei
delle librerie di pianificazione principali
utilizzando una logica simile. Speriamo che questo porterà
sviluppatori che utilizzano questi framework per poter trarre vantaggio da isInputPending()
dietro le quinte senza modifiche significative.
Fornire non è sempre un cattivo segno
Vale la pena notare che produrre meno non è la soluzione giusta per ogni utilizzo per verificare se è così. Esistono diversi motivi per restituire il controllo al browser oltre che per elaborare eventi di input, ad esempio eseguire il rendering ed eseguire altri script della pagina.
Esistono casi in cui il browser non è in grado di attribuire correttamente lo stato "In sospeso"
di input. In particolare, l'impostazione di clip e maschere complesse per multiorigine
Gli iframe potrebbero segnalare falsi negativi (ad es. isInputPending()
potrebbe restituire inaspettatamente
false quando si sceglie come target questi frame). Assicurati di cedere abbastanza spesso se
il tuo sito richiede interazioni con frame secondari stilizzati.
Presta attenzione anche alle altre pagine che condividono un loop di eventi. Su piattaforme come
come Chrome per Android, è piuttosto comune che più origini condividano
ciclo. isInputPending()
non restituirà mai true
se l'input viene inviato a un
multiorigine, pertanto le pagine in background potrebbero interferire con il
reattività delle pagine in primo piano. Potresti voler ridurre, posticipare o cedere
quando si lavora in background utilizzando l'API Page Visibility.
Ti invitiamo a utilizzare isInputPending()
con discrezione. Se non sono
bloccare gli utenti e interagire con gli altri nel loop degli eventi
cedendo con maggiore frequenza. Le attività lunghe possono essere dannose.
Feedback
- Lascia un feedback sulle specifiche nel is-input-pending.
- Contatta @acomminos (uno degli autori delle specifiche) su Twitter.
Conclusione
Siamo entusiasti del lancio di isInputPending()
e che gli sviluppatori possano
per iniziare a utilizzarlo oggi stesso. Questa API è la prima volta che Facebook crea un
una nuova API web e l'abbiamo passata dall'incubazione delle idee alla proposta di standard
la spedizione in un browser. Vorremmo ringraziare tutti coloro che ci hanno aiutato
e ringraziare in modo speciale tutti i membri di Chrome che ci hanno aiutato a dare il meglio di noi
questa idea e fartela spedire!
Foto hero di Will H McMahan su Rimuovi schermo.