مرحبا. في مقالات سابقة، تحدثنا عن الأمور الأساسية لتحسين: واحد و اثنين . أقترح اليوم الغوص في جزء واحد من المهام التي يقوم بها فريق هندسة الواجهة الأمامية في hh.ru.
أنا أعمل في فريق الهندسة المعمارية. نحن لا ننقل الملفات من مجلد إلى آخر فحسب ، بل نقوم أيضًا بمجموعة من الأشياء الأخرى:
- أداء التطبيق
- البنية التحتية: التجميع ، والاختبارات ، وخطوط الأنابيب ، والانتقال إلى الإنتاج ، وأدوات المطور (على سبيل المثال ، ملحقات Babel ، وقواعد eslint المخصصة)
- نظام التصميم (UIKit)
- الانتقال إلى التقنيات الجديدة
إذا بحثت في الأرجاء ، ستجد الكثير من الأشياء الممتعة.
لذلك ، دعونا نتحدث عن الأداء. فريق هندسة الواجهة الأمامية مسؤول عن كل من الواجهة الأمامية والخلفية (SSR).
أقترح النظر في المقاييس وفهم كيفية استجابتنا للمحفزات المختلفة. سيتم تقسيم المقال إلى جزئين. الخادم والعميل. يتم إرفاق الرسوم البيانية ، الكود و coolstory.

في هذه المقالة سوف نتحدث عن كيفية تتبعنا ، وما هي النتائج (المثيرة للاهتمام) الموجودة. للنظرية ولماذا من الأفضل الرجوع إلى المقال الأول.
زبون
— . , , , . - , .
. . , , , . . :
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. , , , , . - . : , , , \ , .
.