Performance
Knowledge points related to frontend performance optimization.
Updated
Web Application Performance Optimization Analysis
A web application is slow for basically two reasons:
- Long computation time: weak CPU capability
- Network latency: weak I/O capability
So, in the end, web application performance optimization is computation optimization, I/O optimization, and similar work performed under limited CPU computing power and limited I/O.
Computation Optimization
There are two lines of thinking for computation optimization:
- Use asynchronous computation: avoid freezing the main thread, and use visual means to tell the user that computation is running in the background, such as operation loading, background task queues, message echo, and similar solutions.
- Reduce the amount of computation: for example, optimize algorithms to lower time complexity; or compute with higher-performance WASM or more powerful FaaS.
I/O Optimization
From the I/O perspective, you need to consider optimizing network I/O capability. This is full-link performance optimization, and most frontend developers focus their optimization efforts on this part.
Common entry points include:
- Back-end interface performance: mainly relies on server-side monitoring and reporting; generally the frontend only needs to care in scenarios like BFF, for example:
- Concurrency performance problems with a single GraphQL interface; optimizing this requires high-availability deployment of NodeJS, with load balancing through Nginx or other gateway services to reduce the load on a single NodeJS application.
- A single-CPU NodeJS process handling CPU-intensive tasks affects the response of other requests, such as chart generation, big-data reads and writes, and so on; the optimization approach is the same as above.
- I/O performance problems when the gateway handles large requests, including file uploads and downloads, and scenarios that need to pass large numbers of parameters; the main optimization point here is the Nginx gateway.
- Consider server stability and availability, avoiding a single point of failure that avalanches the whole cluster.
- Network transfer speed: consider the whole network transmission link, including TCP/TLS handshakes, characteristics of HTTP protocol versions, gzip/br compression, negotiated caching, Range transfer for large files, and so on
- Protocol-layer optimization:
- Prefer HTTP/3: the HTTP+TLS handshake takes only 1 RTT, transmission has no head-of-line blocking, and it supports modern capabilities such as header compression, multiplexing, and connection reuse when mobile devices switch base stations
- Next, consider HTTP/2 multiplexing: concurrent requests do not need repeated handshakes, and it supports header compression and multiplexing
- Finally, consider enabling session caching in Nginx, so reconnections within a certain period skip the handshake
- Transfer-process optimization:
- Enable transfer compression: prefer br, then gzip; Nginx can be used, which negotiates the resource type with the client at request time.
- If using HTTP/1.1 or lower, consider merging interfaces to reduce the number of simultaneous connections and handshake overhead.
- Reduce resource size: improve the user experience through deferred loading of non-critical resources, prioritizing MVP resources, skeleton screens, and similar approaches
- Protocol-layer optimization:
- Cache optimization: reduce server load through multi-level caching while also speeding up client loading, such as CDN, Nginx caching, and so on; watch out for the thundering-herd problem on cache miss
- Set up multi-level caching with different expiration intervals at each node along the transmission path
- Lock when hot resources go back to the origin, avoiding concentrated origin requests that could take down the origin server
- Prefer serving expired cache first, then update the cache during idle time (SWR)
- Load in advance: based on tracking data or user profiles, preload / prefetch / modulepreload the resources a user is likely to visit during idle time
- preload has high priority and is suitable for resources likely to be visited soon
- prefetch has low priority, but the thread can keep loading after the page is closed
- modulepreload is the same as preload, but with fewer RTTs, loading all dependent chunks back in one go
Image Optimization
Introduction to Image Formats
jpg: a lossy compression format; does not support transparency- Suitable for: rich colors, colorful photos, banner images, irregularly structured graphics
- Not suitable for: line graphics, text, icons
png: a losslessly compressed bitmap format; supports indexed color, grayscale, RGB, and transparency- Suitable for: solid colors, transparency, line graphics, sharp edges with large areas of identical color, semi-transparency with few colors
- Not suitable for: colorful images, which would be very large
gif: only supports fully transparent or fully opaque; only 8-bit color, 256 colors in total- Suitable for: animations, icons
- Not suitable for: colorful images
webp: a modern image format supporting lossless and lossy compression, small size, animation, transparency, 8-bit color- Suitable for: graphics, semi-transparency, animations
- Not suitable for: images with rich colors
svg: vector images supporting animation, transparency, and color- Suitable for: scenarios that need scaling, where display quality is guaranteed
- Not suitable for: irregular line art, which inflates file size; use with caution when images are nested, as size grows large.
Optimizing Load Speed
Common optimization methods:
- Image compression:
jpg:jpegtranpng:node-pngquant-nativegif:gifsicle
- Adaptive image sizes: fetch images of different sizes from the server through query parameters; cropping by resolution speeds up image loading on small-screen devices and avoids blurriness on large screens
- Progressive image loading: initially use placeholders such as a unified placeholder, low-quality images, or vector placeholders, then progressively load and replace with high-quality images
- Small image optimization:
- Inline via Data URI to reduce the number of requests
- Merge images with sprites
HTML Performance Optimization
- Reduce HTML code length:
- Reduce DOM depth
- Reduce the number of DOM nodes
- Remove protocol headers (
//a.comautomatically completes the protocol based on the current site's protocol) - Remove extra spaces, indentation, and comments
- Use relative paths for same-origin URLs
- Consider resource request blocking
- Prioritize loading the CSS and JS needed for the first screen; preload other content via preload/prefetch
- Put CSS in head whenever possible; defer JS with defer, see Resource loading priority
- Render the first screen first with SSR to reduce reflows
CSS Performance Optimization
- CSS rendering performance
- Reduce selector depth
- Reduce CSS expressions
- Avoid wildcards, regex attribute matching, and so on
- Reduce
@import
- CSS animation optimization
- Prefer the transform property for movement instead of directly modifying geometric properties, to avoid large-scale reflows
- For unavoidable animations on geometric properties, use
will-changeto notify the browser
JS Performance Optimization
- JS execution performance optimization:
- Use the id selector to get elements precisely
- Avoid
evalandwith - Throttle user interaction events
- Use event delegation for list events
- JS animation optimization:
- Prefer CSS animations or canvas animations
- Use
requestAnimationFramefor timely UI updates
- DOM node caching:
- Simulate long lists with a virtual list to avoid rendering large numbers of DOM nodes at once
webpack Performance Optimization
Browser Loading Mechanism
Network Request Optimization
- Reduce the content stored in Cookies
- Switch the https certificate to an ECC certificate
- Upgrade TLS to 1.3 (supports 0-RTT handshake)
- Upgrade the network protocol to HTTP/2 or HTTP/3
- Use a CDN to host static resources