Hola. En artículos anteriores, hablamos sobre los aspectos básicos de la optimización: uno y dos . Hoy propongo sumergirnos en una parte de las tareas que está realizando el equipo de arquitectura frontend de hh.ru.
Trabajo en el equipo de arquitectura. No solo transferimos archivos de una carpeta a otra, sino que también hacemos muchas otras cosas:
- Rendimiento de la aplicación
- Infraestructura: ensamblaje, pruebas, canalizaciones, implementación en producción, herramientas de desarrollo (por ejemplo, complementos de babel, reglas de eslint personalizadas)
- Sistema de diseño (UIKit)
- Pasar a nuevas tecnologías
Si investigas, puedes encontrar muchas cosas interesantes.
Por tanto, hablemos de rendimiento. El equipo de arquitectura de frontend es responsable tanto del front end como del back end (SSR).
Sugiero mirar las métricas y comprender cómo respondemos a los diferentes factores desencadenantes. El artículo se dividirá en 2 partes. Servidor y cliente. Se adjuntan gráficos, código y coolstory.
En este artículo hablaremos sobre cómo rastreamos, qué resultados (interesantes) hay. Para la teoría y por qué es mejor consultar el primer artículo.
Cliente
— . , , , . - , .
. . , , , . . :
FMP (first meaningful paint)
FMP : . — . TOP . 95 . .
, :
FMP :
- hh.ru — . , , , — , .
- — . — .
FMP — . FMP? .
, FMP - :
requestAnimationFrame(function() {
// renderTree
var renderTreeFormed = performance.now();
requestAnimationFrame(function() {
//
var fmp = performance.now();
//
window.globalVars.performance.fmp.push({
renderTreeFormed: renderTreeFormed,
fmp: fmp
})
});
});
:
- body, ( , 1 ). , .
- — ¯(ツ)/¯
, raf setTimeout\interval . .
, - . PageVisibility API:
window.globalVars = window.globalVars || {};
window.globalVars.performance = window.globalVars.performance || {};
// ,
window.globalVars.performance.pageWasActive = document.visibilityState === "visible";
document.addEventListener("visibilitychange", function(e) {
// - —
if (document.visibilityState !== "visible") {
window.globalVars.performance.pageWasActive = false;
}
});
FMP:
requestAnimationFrame(function() {
// renderTree
var renderTreeFormed = performance.now();
requestAnimationFrame(function() {
//
var fmp = performance.now();
// ,
// ,
if (window.globalVars.performance.pageWasActive) {
window.globalVars.performance.fmp.push({
renderTreeFormed: renderTreeFormed,
fmp: fmp
});
}
});
});
, . .
: — , " " , . .
, , ? , , renderTree () , , , .
. ( fmp_menu ):
<script>window.performance.mark('fmp_body')</script>
:
: , .
:
- FMP . , 3 . "" .
- FMP: 10 . .
- , FMP . , .
- , ! , url-. , , 95 :
, . , , .
TTI
TTI . , Page Visibility API, . , TTI longtask " - -", , .
function timeToInteractive() {
// TTI
const LONG_TASK_TIME = 2000;
// TTI,
const MAX_LONG_TASK_TIME = 30000;
const metrics = {
report: 'TTI_WITH_VISIBILITY_API',
mobile: Supports.mobile(),
};
if ('PerformanceObserver' in window && 'PerformanceLongTaskTiming' in window) {
let timeoutIdCheckTTI;
const longTask = [];
const observer = new window.PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
longTask.push(Math.round(entry.startTime + entry.duration));
}
});
observer.observe({ entryTypes: ['longtask'] });
const checkTTI = () => {
if (longTask.length === 0 && performance.now() > MAX_LONG_TASK_TIME) {
clearTimeout(timeoutIdCheckTTI);
}
const eventTime = longTask[longTask.length - 1];
if (eventTime && performance.now() - eventTime >= LONG_TASK_TIME) {
if (window.globalVars?.performance?.pageWasActive) {
StatsSender.sendMetrics({ ...metrics, tti: eventTime });
}
} else {
timeoutIdCheckTTI = setTimeout(checkTTI, LONG_TASK_TIME);
}
};
checkTTI();
}
}
export default timeToInteractive;
TTI (95", TOP ):
: TTI ? :
- , requestIdleCallback
- 3d party
, " ". :
()
95" TOP :
? , JS , .
, js , , , .
JS
, hydrate
, , :
, :
- , , ( \ , - )
- — . , :
?
- FMP, , . , , SSR .
- , . . .
LongTasks
PerformanceObserver :
:
, , (, 2020!). : ! . .
: , js reflow, event loop 30 .
, . , . , ;)
2 :
- ,
- Longtasks. — .
?
, . -, , rate + , , FID. .
, .
. — . , .
? , .
, , CPU, — . SSR. :
http
— , TOP . 95 . , 12:10 12:40. " ", 400 , , " ". :
c
, parse time.
CPU. :
, . 1 . .
: . 12 , . 150, 400 .
. . , , slack :
.
render parse time :
, :
,
TypeError: Cannot read property 'map' of undefined
at Social (at path/to/module)
, .
, , , :
, parse time :
. . :
SSR as a service. BFF, node.js , . BFF .
, , , : BFF , node.js. — BFF . , .
BFF . \ .
:
. .
, .
, . . FMP. , , , , . - . : , , , \ , .
.