A szerver gondolkodik, a böngésző már tölt: a HTTP 103 Early Hints

A HTTP 103 Early Hints válasszal a szerver már a render közben elárulja, milyen erőforrásokat fog kérni a böngésző. Megnézzük Node.js demóval, mit tud a CDN-es visszajátszás, és miért mutat a Shopify mobilos mérése épp ellenkező hatást.

Ha egy oldal HTML-je csak adatbázis-lekérdezés vagy szerveroldali render után áll össze, a böngésző addig tétlenül vár: amíg meg nem érkezik az első byte, nem is tudhatja, milyen CSS-t vagy scriptet kell majd letöltenie. A HTTP 103 Early Hints erre a holtidőre épít. A szerver a végleges válasz előtt küld egy ideiglenes üzenetet, amiben elárulja, mit fog kérni a böngésző – az pedig ez alapján már a render közben elkezdi előtölteni azokat.

Idővonal-diagram: felül a hagyományos folyamat, ahol az erőforrások betöltése csak a teljes válasz után indul, alul az Early Hints-szel gyorsított folyamat, ahol az erőforrások már a szerver feldolgozása közben, párhuzamosan töltődnek, és a teljes folyamat rövidebb idő alatt fejeződik be

Egy 1xx-es válasz, ami tényleg csinál valamit

Az 1xx-es státuszkódok informális válaszok: nem zárják le a kérést, csak közbenső üzenetek a végleges válasz előtt. A legismertebb a 100 Continue. A 103-at az RFC 8297 vezette be, és a HTML specifikáció is definiálja, hogyan kell feldolgozni. A lényeg: a szerver küldhet egy vagy több 103-as választ – benne Link fejléccel –, mielőtt elkezdené kiszámolni és elküldeni a tényleges 200 OK-t. A böngésző ezt a Link fejlécet ugyanúgy értelmezi, mintha a HTML <head>-jében lévő <link> elem volna, csak jóval korábban, még mielőtt egyetlen sor HTML megérkezett volna.

Ez pont oda illik, ahol a legtöbb szerveroldali render idejéből elmegy: a sablon maga gyors, de a mögötte lévő adatlekérés, session-ellenőrzés vagy külső API-hívás száz-néhányszáz milliszekundumot elvisz. Eddig ez az idő tisztán holtidő volt a kliens szempontjából. Az Early Hints ezt az időt a kritikus CSS és a fontok előtöltésére fordítja.

Kipróbálva: két válasz, egy kérés

Node.js-ben a http és http2 modul ServerResponse-ja is tud writeEarlyHints()-t hívni – ezt a natív http modulra a v18.11.0-s kiadás terjesztette ki. A metódust writeHead() előtt kell meghívni:

import http from 'node:http';

const server = http.createServer((req, res) => {
  if (req.url === '/') {
    res.writeEarlyHints({
      link: [
        '</style.css>; rel=preload; as=style',
        '</app.js>; rel=preload; as=script',
      ],
    });

    // Ez szimulálja a lassú részt: DB-lekérdezés, render stb.
    setTimeout(() => {
      res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' });
      res.end('<!doctype html><html><body>Kész</body></html>');
    }, 300);
    return;
  }
  res.writeHead(404);
  res.end();
});

server.listen(3999);

A curl -v --http1.1 ugyanazon a TCP-kapcsolaton két választ mutat egymás után:

< HTTP/1.1 103 Early Hints
< Link: </style.css>; rel=preload; as=style, </app.js>; rel=preload; as=script
< HTTP/1.1 200 OK
< content-type: text/html; charset=utf-8
< Transfer-Encoding: chunked

A 103 azonnal megjön, a 200 csak 300 ezredmásodperccel később – pontosan a beépített setTimeout miatt. Egy valós böngésző ez alatt a 300 ms alatt már tölti a stílust és a scriptet, nem a HTML megérkezésére vár.

A böngészőtámogatás nem annyira egyértelmű

A MDN kompatibilitási táblázata szerint a Chrome 103-tól, a Firefox 120-tól, a Safari pedig 17-től érti a 103-as választ – és mindhárom csak HTTP/2 vagy újabb fölött, plain HTTP/1.1-en nem megbízható. Van egy kevésbé ismert csavar is: a Safari a rel=preconnect hintet feldolgozza Early Hintsből, a rel=preload-ot viszont nem. Vagyis ha kizárólag Safarira optimalizálnánk, a kapcsolat felmelegítése működne, de maga az erőforrás előtöltése nem indulna el a 103-ból – csak a végleges HTML feldolgozásakor, a megszokott módon.

A CDN ezt ingyen visszajátssza

Nem kell feltétlenül az alkalmazáskódban implementálni. A Cloudflare Early Hints funkciója megjegyzi, milyen preload/preconnect típusú Link fejléceket küldött az origin egy korábbi 200-as válaszban, és a következő kéréseknél ezeket már a saját éléhálózatából, 103-as válaszként küldi vissza – az origin szerver render-ideje alatt. A Cloudflare saját mérése egy e-kereskedelmi teszttoldalon 530 ezredmásodperccel korábbi largest contentful paintet, 752 ms-mal korábban induló erőforrás-letöltést és 562 ms-mal rövidebb teljes betöltési időt mért Early Hints bekapcsolásával.

Amikor mégsem éri meg

A Shopify saját, üzletek ezreire kiterjedő elemzése árnyalja a képet. Desktopon 1–3 kritikus erőforrás előtöltésénél mértek javulást, ennél többnél a haszon csökkent. Mobilon viszont az Early Hints nélküli oldalak minden percentilisnél jobban teljesítettek, mint az Early Hints-et használók – a jelenség a feldolgozási és hálózati többletterheléssel magyarázható, és négy vagy több előtöltött erőforrásnál különösen kifejezett. A csapat végkövetkeztetése: csak a ténylegesen kritikus, first-viewport-beli erőforrásokat (kritikus CSS, egy-két webfont) érdemes előtölteni, és a hatást valós felhasználói méréssel (RUM) kell ellenőrizni – nem szabad feltételezni, hogy több hint mindig gyorsabb oldalt jelent.

Ez a fajta eredmény jó emlékeztető, hogy az Early Hints nem egy kapcsoló, amit bekapcsolunk és elfelejtünk. Ugyanúgy méréssel validálandó teljesítmény-optimalizálás, mint a preload vagy a resource hints bármelyik másik formája: a szerver oldali think-time-ot hasznosítja, de csak akkor, ha tényleg kritikus, a kezdő megjelenítéshez szükséges erőforrást tölt elő vele – minden más felesleges hálózati terhelés, ami rosszabb eszközön inkább árt, mint használ.

Források

Leave a Reply

Az e-mail címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük