Bonjour. Dans les articles précédents, nous avons parlé des éléments de base de l'optimisation: un et deux . Aujourd'hui, je propose de plonger dans une partie des tâches que fait l'équipe d'architecture frontend de hh.ru.
Je travaille dans l'équipe d'architecture. Nous transférons non seulement des fichiers d'un dossier à un autre, mais nous faisons également un tas d'autres choses:
- Performances des applications
- Infrastructure: assemblage, tests, pipelines, déploiement en production, outils de développement (par exemple, plugins babel, règles eslint personnalisées)
- Système de conception (UIKit)
- Passer aux nouvelles technologies
Si vous creusez, vous pouvez trouver beaucoup de choses intéressantes.
Par conséquent, parlons de performance. L'équipe d'architecture frontend est responsable à la fois du frontend et du backend (SSR).
Je suggère d'examiner les métriques et de comprendre comment nous répondons aux différents déclencheurs. L'article sera divisé en 2 parties. Serveur et client. Les graphiques, le code et la coolstory sont joints.
Dans cet article, nous parlerons de la façon dont nous suivons, des résultats (intéressants). Pour la théorie et pourquoi il est préférable de se référer au premier article.
Client
— . , , , . - , .
. . , , , . . :
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. , , , , . - . : , , , \ , .
.