What happens when you navigate
Trace a browser navigation from typed input through network checks, renderer selection, page commit, service workers, and preload.
- 01Trace a navigationExplain how browser-process input, network work, response decisions, and a renderer fit together in Chrome.
- 02Explain committingDescribe why a page becomes active only after a renderer commits it and browser UI state can update.
- 03Use service worker preloadRecognize when navigation preload overlaps network work with service worker startup and how to consume it.
A navigation is a handoff
Pressing Enter after typing a web address looks instant, but several jobs have to agree before a new page becomes active. The browser handles your input, starts a request, checks what comes back, chooses somewhere to render it, and commits a new document. Only after that does the new page keep loading its HTML, scripts, images, and styles.
A navigation is the browser's process of moving a browsing context from one document to another. A commit is the point where the chosen renderer accepts the new document as the active page.
This lesson uses Chrome's published process model when it says in Chrome. Other browsers use different internal designs, but they solve similar jobs: interpret the request, fetch or provide a response, choose a document context, and activate the result. The JavaScript functions here are small teaching models, not a way to inspect a browser's private processes.
It follows Browser architecture, where browser, renderer, network, and GPU work were separated. It leads into From HTML to running script, which starts after a new document's bytes reach its renderer.
Input in the browser process
Start with a URL as ordinary JavaScript data. Line 1 creates a URL object. Line 2 prints its host name and the value of its item query parameter. The actual output is shop.example tea.
1const url = new URL("https://shop.example/cart?item=tea");2console.log(url.hostname, url.searchParams.get("item"));3 4function classifyInput(text) {5 return text.includes(".") || text.startsWith("http") ? "url" : "search";6}7 8console.log(classifyInput("how to make tea"));9console.log(classifyInput("shop.example/cart"));Line 4 starts a deliberately tiny input model. Line 5 says that text with a dot or an HTTP prefix looks URL-like; other text looks like a search. Therefore, line 8 prints search for how to make tea, and line 9 prints url for shop.example/cart. A real address bar has more rules, including search settings, URL fixes, and security checks.
In Chrome, the address bar belongs to the browser process. Its UI thread handles the typed input and asks whether it is a search query or a URL. That matters because the destination renderer may not exist yet. The browser needs to decide what to ask the network for before it can give any HTML to a page process.
You type what you want, then the app decides where to send the order. That first decision happens before food is prepared or delivered.
- In real life: You type a dish or restaurant
- In JavaScript: You type a URL or a search
- In real life: The app contacts the restaurant
- In JavaScript: The browser starts a network request
- In real life: A delivery person is assigned
- In JavaScript: A renderer is chosen or started
- In real life: Food reaches your door
- In JavaScript: The new document commits
Where the analogy stops: A browser has security, process, and network rules that a delivery order does not model.
Start the network request
After you confirm the input, a navigation request begins. In Chrome, the UI thread starts the work and the network thread handles network protocols such as DNS lookup and Transport Layer Security, usually called TLS, connection setup. The tab can show loading progress while this happens.
1const typed = "how to make tea";2const kind = typed.includes(".") ? "url" : "search";3const request = kind === "url" ? typed : "https://search.example/?q=" + encodeURIComponent(typed);4console.log(request);Line 1 stores ordinary user text. Line 2 identifies it as a search in this small model. Line 3 builds the request URL, and line 4 prints https://search.example/?q=how%20to%20make%20tea. Encoding prevents spaces and other characters from changing the request URL.
The network request is not a promise that this exact URL will render. A server can redirect it. In Chrome's published example, a 301 response tells the network thread about a redirect, and a new request begins. A cross-site redirect can also change which renderer will be suitable, so browser work overlaps instead of waiting at every boundary.
Step through a replay of the lesson's navigation teaching model. It calls the real functions shown here; it is not a browser-process debugger.
script
2const kind = classifyInput(typed);3const request = kind === "url" ? typed : "https://search.example/?q=" + typed;4const response = { status: 200, contentType: "text/html" };5 6function navigate(input) {7 const kind = classifyInput(input);8 const request = kind === "url" ? input : "https://search.example/?q=" + input;9 const decision = responseDecision(response.status, response.contentType);10 const renderer = decision.action === "render" ? "renderer ready" : "not needed";11 return { kind, request, decision: decision.action, renderer, committed: decision.action === "render" };12}13 14console.log(navigate(typed));Read and classify the response
A response has a status, headers, and bytes. A Content-Type header says what kind of data the server intended to send. In Chrome's described path, the network layer can inspect the header and, when needed, initial bytes before deciding whether the data is a document for a renderer or a download for a download manager.
1function decide(status, contentType, location) {2 if (status >= 300 && status < 400 && location) return "follow redirect";3 if (status === 204) return "stay on current page";4 if (contentType.includes("text/html")) return status >= 400 ? "render error page" : "render";5 return "download";6}7 8console.log(decide(200, "text/html"));Line 2 handles a redirect with a Location value. Line 3 handles 204, which has no document body to replace the current page in this teaching model. Line 4 handles HTML, including an HTML 404 page. Line 5 leaves non-HTML data for download handling. Line 8 prints render because 200 HTML is a document response.
| Response | Meaning | Model action |
|---|---|---|
| 200 + text/html | A document response | Choose a renderer and render the document. |
| 204 | No document body to replace the page | Stay on the current document in this teaching model. |
| 301 + Location | A redirect response | Start another request for the Location URL. |
| 404 + text/html | An HTML error document | Render the server-provided error page. |
| 200 + application/zip | A non-document file | Hand it to download handling in this teaching model. |
The playground changes one response at a time. It is intentionally smaller than a browser. It does not try to model redirects with many policies, Content Security Policy, Safe Browsing, MIME sniffing, permissions, or every HTTP rule. It teaches the useful question first: what response can become the next document?
1function decide(status, contentType, location) {2 if (status >= 300 && status < 400 && location) return "follow redirect";3 if (status === 204) return "stay on current page";4 if (contentType.includes("text/html")) return status >= 400 ? "render error page" : "render";5 return "download";6}7 8console.log(decide(200, "text/html"));200The response status selected by the reader.
text/htmlThe model uses this to choose a document or download path.
renderHTML document
200 text/html: HTML can be passed to a renderer for a new document.
Find a renderer process
A renderer process is where a document can load HTML and later run page JavaScript. In Chrome, once the network thread has response data that is ready for navigation, it tells the UI thread. The UI thread finds a renderer process to carry on rendering the page.
1const decision = "render";2const renderer = decision === "render" ? "renderer ready" : "not needed";3console.log(renderer);4console.log(decision === "render");Line 1 names the earlier response decision. Line 2 chooses a readable model state. Line 3 prints renderer ready, and line 4 prints true. This is not a process-selection API. Web page code cannot choose a Chrome renderer process.
Chrome can optimize this handoff. When its UI thread starts the URL request, it already knows the likely destination site. It can proactively find or start a renderer while network work is still in flight. If a redirect crosses to another site, that early renderer might not be used, but starting early can save time on the common path.
Site isolation and process selection are browser security and reliability decisions. A page can observe web APIs such as location, history, and performance entries, but it cannot ask for a particular internal renderer process.
Commit the navigation
Commit is the clear boundary between preparing a possible destination and activating a new document. In Chrome, when response data and a renderer are ready, the browser process sends an inter-process communication message, often shortened to IPC, asking the renderer to commit. It also passes the data stream so the renderer can continue receiving HTML.
1const oldPage = "cart";2const newPage = "checkout";3 4function commitNavigation(oldDocument, newDocument) {5 const addressBar = "/checkout";6 const history = ["/cart", addressBar];7 const oldPageEvent = "unload";8 return { addressBar, history, oldPageEvent, document: newDocument };9}10 11console.log(commitNavigation(oldPage, newPage).addressBar);Lines 1 and 2 name the old and new documents. Line 5 gives the address bar its new URL. Line 6 appends that URL to session history. Line 7 labels old-page lifecycle work. Line 11 prints /checkout. The model shows visible state, not a replacement for browser history internals.
| Stage | What is ready | What changes |
|---|---|---|
| Navigation starts | A request has begun | The old page is still the active document. |
| Response is ready | Browser checks allow a document | A suitable renderer is selected or started. |
| Commit | Browser process tells the renderer to commit | Address bar and session history can update. |
| Document loading | The renderer receives HTML and subresources | Parsing, scripts, and rendering continue after the commit. |
Replay a small commit model. It explains visible browser state changes without claiming that JavaScript can observe Chrome's private IPC messages.
script
2const newPage = "checkout";3 4function commitNavigation(oldDocument, newDocument) {5 const addressBar = "/checkout";6 const history = ["/cart", addressBar];7 const oldPageEvent = "unload";8 return { addressBar, history, oldPageEvent, document: newDocument };9}10 11console.log(commitNavigation(oldPage, newPage).addressBar);When navigating away, the browser may need to ask the old renderer about beforeunload first. After a new cross-site navigation, Chrome can keep the old renderer briefly for unload-related work. For application lifecycle behavior, continue with Page lifecycle; avoid treating unload as a reliable last-second database save.
Load the new document
Commit does not mean every byte has finished loading. It means the renderer has accepted the new document. It can keep receiving HTML, parse it, request subresources, create the document structure, and eventually run scripts. Client-side JavaScript can keep fetching and changing the page even after a browser stops its loading indicator.
1const entry = performance.getEntriesByType("navigation")[0];2console.log(entry ? entry.type : "no navigation entry here");Line 1 asks the Performance API for the first navigation timing entry. Line 2 prints its type when available, such as navigate, or prints no navigation entry here when there is no entry in the current environment. The feature check keeps the snippet safe in a browser sandbox or non-document context.
This entry is useful for measuring web-visible timing, but it does not show private browser-process messages. Treat it as evidence about the page's navigation, not proof of one browser's exact internal scheduler. The next lesson picks up with how received HTML finds and runs scripts.
Service workers change the path
A service worker is application JavaScript that can act as a network proxy for pages in its scope. During a matching navigation, the browser can start the worker and dispatch a fetch event. The worker may return a cached response, a network response, or another response it constructs.
1async function responseFor(cached, network) {2 if (cached) return "cache";3 await network;4 return "network";5}6 7responseFor(true, Promise.resolve()).then(console.log);Line 1 receives a cached value and a network promise. Line 2 returns immediately when a cache has a response. Lines 3 and 4 wait for the network only when needed. The final line prints cache. A real service worker returns Response objects, but the small strings make the choice easy to see.
In Chrome's process description, the network thread checks registered service-worker scopes. If the URL matches, the browser can arrange for service-worker code to run in a renderer process. A cache response can avoid a network request. A network-first worker, however, can add startup delay before it starts fetching.
Navigation preload overlaps work
Navigation preload helps when a service worker will eventually need the network. Without it, a navigation can wait for a stopped worker to start before the worker begins its network fetch. With preload enabled, the browser begins an eligible GET navigation request while the service worker is starting, so the two waits overlap.
1addEventListener("activate", (event) => {2 event.waitUntil((async () => {3 if (self.registration.navigationPreload) {4 await self.registration.navigationPreload.enable();5 }6 })());7});8 9addEventListener("fetch", (event) => {10 event.respondWith((async () => {11 const cached = await caches.match(event.request);12 if (cached) return cached;13 const preloaded = await event.preloadResponse;14 return preloaded || fetch(event.request);15 })());16});Line 2 waits for activation work. Line 3 feature-detects the navigation preload manager. Line 4 enables preload. In the fetch handler, line 13 waits for event.preloadResponse, and line 14 uses it when present before doing a normal fetch. This is service-worker code, so it is shown for reading rather than run in the page sandbox.
The important detail is consuming the preload response. Enabling preload and then always calling fetch(event.request) can create two requests. The preloaded response resolves to a Response for eligible navigation requests when preload is enabled; otherwise it can resolve to undefined, which is why the fallback fetch remains.
The useful saving is overlap. The restaurant starts cooking as the helper wakes up to check coupons, rather than waiting for the helper before the kitchen begins.
- In real life: You tap Order
- In JavaScript: A navigation request begins
- In real life: The restaurant starts cooking
- In JavaScript: Preload starts the network request
- In real life: A helper opens the coupon screen
- In JavaScript: The service worker starts
- In real life: The helper uses the ready food
- In JavaScript: The fetch handler uses preloadResponse
Where the analogy stops: A preload request has browser eligibility rules and response headers that a food order does not have.
Use navigation facts in real apps
These internals make several frontend choices easier to explain. A redirect can mean the browser starts another request before rendering. A document is usable after commit, but its images and scripts may still be loading. A service worker cache can make a navigation fast, while a network-first worker should consider preload when cold startup delays the request.
- Save important draft data as the user edits instead of depending only on exit events.
- Use the Performance API to measure web-visible navigation timing, not guessed browser-process timings.
- Handle redirects and error pages as normal response paths in product flows.
- Use service-worker caches deliberately, then consume preload responses when preload is enabled.
- Keep page loading and route-level loading states honest: commit is not full resource completion.
- Classifying address-bar text as search or URL
- Starting the navigation network request
- Sending the instruction to commit a navigation
- Receiving HTML and loading the document
- Running the new page's JavaScript
- Choosing a cached or preloaded navigation response
Sort each card by the part of Chrome's described navigation design that owns it.
This is a useful boundary for debugging. A script cannot repair a server redirect by repainting faster, and a renderer cannot make a cold service worker start sooner by changing a CSS rule. Find which handoff is slow before choosing a tool.
Common misconceptions
- “Enter immediately replaces the page.” A request, response checks, renderer choice, and commit come first.
- “Commit means every resource is loaded.” Commit activates the document; parsing and subresource loading continue.
- “A redirect is a rendered error.” A redirect asks the browser to request another URL before a document is committed.
- “A service worker always makes navigation faster.” A cold network-first worker can add startup delay without preload.
- “Navigation preload replaces the fetch handler.” The handler must use
event.preloadResponseor choose another response.
| Word | What it means | What it does not mean |
|---|---|---|
| Request | Ask a server or worker for a resource | The new page is already active |
| Response | Status, headers, and bytes returned | The response must be HTML |
| Commit | A renderer accepts the next document | All page resources have completed |
| Navigation preload | Network starts alongside worker startup | The worker can ignore preloadResponse safely |
Practice exercises
Run the tiny URL program mentally, then type the two values it prints.
const url = new URL("https://shop.example/cart?item=tea");
console.log(url.hostname, url.searchParams.get("item"));It prints shop.example tea. The URL object separates the hostname from the query parameter value.
How does the lesson model classify how to make tea?
The answer is search. how to make tea has no dot or HTTP prefix in this model.
Predict the output, then explain what real browser work follows it.
function decide(status, location) {
return status === 301 && location ? "follow redirect" : "render";
}
console.log(decide(301, "/new-cart"));It prints follow redirect. A redirect leads to another request rather than directly committing a document.
A request receives 204. What should the response playground model do?
The model stays on the current page. This is a teaching decision for a no-content response, not a complete specification of every navigation edge case.
Explain why a network-first service worker might enable navigation preload.
Navigation preload starts the network request while the service worker starts. The fetch handler can then use event.preloadResponse when it is ready.
Your checkout form has an address draft. What should the app save before a user leaves?
Save important user data as the user edits. Navigation lifecycle events are useful signals, but essential drafts should not depend only on leaving the page.
Check your understanding
Work from the visible path: input, request, response decision, renderer, commit, then loading or service-worker handling.
Question 1 of 7In Chrome, which part first handles text typed in the address bar?
Choose an answer to see the explanation.
Question 2 of 7What does this print?
Read the code, then predictPop out in the code editor (opens in a new tab)JavaScriptconst url = new URL("https://shop.example/cart?item=tea"); console.log(url.hostname, url.searchParams.get("item"));Choose an answer to see the explanation.
Question 3 of 7A navigation receives a 301 response with a Location header. What happens in this lesson's model?
Choose an answer to see the explanation.
Question 4 of 7Why can Chrome prepare a renderer before response bytes arrive?
Choose an answer to see the explanation.
Question 5 of 7What changes at commit in Chrome's described navigation path?
Choose an answer to see the explanation.
Question 6 of 7What does navigation preload avoid when a service worker needs the network?
Choose an answer to see the explanation.
Question 7 of 7What does this feature-detected snippet print when no navigation entry exists?
Read the code, then predictPop out in the code editor (opens in a new tab)JavaScriptconst entry = undefined; console.log(entry ? entry.type : "no navigation entry here");Choose an answer to see the explanation.
Key takeaways
- In Chrome, address-bar input starts in the browser process, which distinguishes a search from a URL.
- A navigation response can render, redirect, leave the current document, show an error document, or become a download.
- Chrome can prepare a renderer while the network request is in flight, then send a commit IPC when both are ready.
- Commit activates the new document and lets address-bar and history state update; resource loading continues afterward.
- Service workers can provide navigation responses, and navigation preload overlaps network work with worker startup.
- Measure page-visible facts with browser APIs and use process explanations to choose the right debugging layer.
Remember the one-liner.
A navigation becomes a new page only when a suitable response reaches a renderer and that renderer commits it.
Coming next: From HTML to running script, where the renderer turns a committed document's bytes into parser work, fetches, and JavaScript execution.