Browser performance optimization
Correct resource download/execution priority and reduce browser idle time during page loading are one of the most important means to improve web application performance. In actual web applications, this optimization scheme has proven to be more direct and effective than reducing code size. This type of optimization has a relatively small impact on the pace of product development, and it only requires a small amount of code changes and refactoring.
Javascript
, XHR
, picture preload
Let the browser preload dynamic resources on key pages: dynamically loaded JavaScript, preloaded XHR-GraphQL data request .
<link rel="preload" href="index.js" as="script" type="text/javascript">
Dynamic loading of JavaScript
usually refers to the script loaded by the router for the specified client import('...')
When the server receives the request, it can know which client-side routing dynamic scripts will be needed for this specific server-side entry file, and add preloading logic for these scripts in the HTML that is initially rendered on the page.
In a certain page entry file, a specific GraphQL request will inevitably be executed. This XHR request can be preloaded. This is very important because in some scenarios, GraphQL requests will consume a lot of time, and the page must wait until the data is loaded. To start rendering.
<link rel="preload" href="/graphql/query?id=12345" as="fetch" type="application/json">
Benefits of adjusting preload priority
In addition to starting resource loading earlier, preloading has additional benefits: it increases the network priority of asynchronous script loading. This is very important for important [asynchronous scripts], because their network priority is low
default. This means that their priority is the same as that of pictures outside the screen ( low
), while the XHR
request of the page and the network priority of pictures inside the screen are higher than them ( high
). This may cause the loading of important scripts required for page rendering to be blocked or share bandwidth with other requests.
The problem of adjusting the preload priority
The problem of preloading: The additional control it provides brings additional responsibility, namely setting the correct resource priority. When the low-speed mobile network in the area, slow WIFI network or packet loss rate is relatively high in the test scenario, <link rel="preload" as="script">
network request priority than <script />
label JavaScript
high scripts, <script />
script tag page rendering is needed first, This will increase the load time of the entire page.
Only preload the asynchronous JavaScript
package required by the routing
Routing the current page through the client needs to be loaded asynchronously.
- Preload all
JavaScript
resources. - Control the order of loading
JavaScript
Picture preload
Construct an abstraction of priority tasks to handle asynchronous loading queues. This preload task is initialized with a priority of idle
(using the requestIdleCallback
function, the window.requestIdleCallback()
method will queue the functions called during the browser’s idle period. It is executed on the main event loop. Work in the background and low priority without affecting delayed key events, such as animation and input response.), so it will not start until the browser is not performing any other important tasks. The way to increase the priority is to cancel all idle tasks to be executed, so that the preloaded tasks can be executed immediately.
Use early flush
(refresh in advance) and progressive HTML
(progressive HTML
) to push data
How to make the browser initiate a request before HTML
The solution is to take the initiative to push the resource server to the browser, which is a bit like using the http/2
of push
properties, it has a very good browser compatibility, and do not need to implement this feature increases the complexity of the server infrastructure.
Its main realization includes two points:
HTTP
block transfer coding- Browser progressive rendering
HTML
Chunked transfer encoding is HTTP/1.1
protocol. In essence, it allows the server to HTTP
the return of chunk
into multiple 060a784aed3c0c (blocks), and then transfer them to the browser in the form of a stream. The browser continuously receives these blocks and aggregates them together after the last block arrives.
It allows the server to stream the content of the HTML
chunk
, without waiting for the entire HTML
complete. The server receives a request, it can be HTML
head flush
to the browser (early flush), reduces the processing HTML
remaining time content. For the browser, when the browser receives HTML
, it starts to preload static resources and dynamic data. At this time, the server is still busy generating the HTML
Use [Block Transfer Coding] to push other data to the client at the same time as the transmission is completed. Web server for rendering applications, generally use HTML
format returned; for SPA
, can JSON
format of data to be pushed to the browser.
Create a JSON
cache to store the data returned by the server.
// 服务端将会写下所有它已经在准备的请求路径
// 这样客户端就知道等待服务端返回数据即可,不需要自己发送XHR请求
window.__data = {
'/my/api/path': {
// 客户端发起请求后的回调都存在waiting数组中
waiting: []
}
};
window.__dataLoaded = function (path, data) {
const cacheEntry = window.__data[path];
if (cacheEntry) {
cacheEntry.data = data;
for (let i = 0; i < cacheEntry.waiting.length; i++) {
cacheEntry.waiting[i].resolve(cacheEntry.data);
}
cacheEntry.waiting = [];
}
};
In the HTML
refresh the browser, the server can perform their own API
query request, when completed, will JSON
data to [include script
label HTML
refresh the page fragment] form. When this HTML
fragment is received and parsed by the browser, it will be written into the JSON
cache object. Here is a key technical point: the browser will start rendering as soon as it chunks
API
data can be generated on the server side in parallel, and when each API
data is ready, it will be refreshed to the JS block immediately.
When the client JS is ready to request a specific data, it will first check whether there is data in the JSON cache object, instead of initiating an XHR request. If there is data in the JSON cache object, it will be returned immediately; if the JSON cache object has been marked with pending
, it will resolve
callback into the corresponding waiting
array, and execute the corresponding resolve
callback after the request is completed.
function queryAPI(path) {
const cacheEntry = window.__data[path];
if (!cacheEntry) {
// 没有缓存对象,直接发起一个普通的XHR请求
return fetch(path);
} else if (cacheEntry.data) {
// 服务端已经推送好数据
return Promise.resolve(cacheEntry.data);
} else {
// 服务端正在生成数据或推送中
// 把请求成功的resolve回调放到cacheEntry.waiting队列中
// 当接收到数据后,回调会按顺序执行
const waiting = {};
cacheEntry.waiting.push(waiting);
return new Promise((resolve) => {
waiting.resolve = resolve;
});
}
}
The effect of this optimization is very obvious: the time it takes for desktop users to access the page to complete the rendering is reduced by 14%, and for mobile users (with higher network latency) it is reduced by 23%.
Cache first
How to make the page get data faster? The only idea is to request and push data without going through the network. Can be achieved by using a cache-first rendering mechanism
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。