9
头图

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.

  1. Preload all JavaScript resources.
  2. 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


寒青
10.4k 声望3.8k 粉丝

« 上一篇
开发插件集合
下一篇 »
前端开发工具