- Multiple data sources
- Serial requests to render a module
- Operational data and personalized data matching and management
- Data bottom-pocket Dr
Taobao home page revision, although no longer support IE6 and IE7 and other lower versions of the antique browser, but there are still a number of factors affecting the performance of the home page:
- The data request is divided into three parts. One is static resources (such as JS/CSS /image/iconfont, etc.). The second is the static data pushed to the CDN (such as the data filled in by the operation, front-end configuration information, etc.); The third is the back-end interface, different modules correspond to different business, and there are a lot of advertising content in the page, rough estimation when the page is just loaded, the first screen issued interface requests have 8, roll to the bottom, have to issue more than 20 requests.
- The first screen data cannot be directly output. A lot of the first screen data is obtained through asynchronous requests. Due to system limitations, these requests are unavoidable and there are a large number of requests, which greatly affects the first screen time.
- There are too many modules. In order to fill in data permissions between background isolation operations, modules must be split in fine granularity, as shown in the figure below:
- There are too many pictures. If you scroll down the page, it is obvious that the whole screen of the page is full of pictures. Some pictures are filled in by the operation, and some pictures are provided by the personalized interface.
Web page performance metrics
There are a lot of web performance measurement indicators, if we can grasp the key several, centralized optimization, performance will naturally go up.
FPS
One of the indicators that can best reflect page performance is frame per second (FPS). Generally, the system sets the screen refresh rate at 60 FPS. When the page element animation, scrolling or gradient is less than 60, it will not be smooth; when it is less than 24, it will stall; when it is less than 12, it is basically considered to be jammed.
The length of a frame is about 16ms, excluding the overhead of system context switch, each frame only leaves us about 10ms of program processing time. If the processing time of a script exceeds 10ms, then this frame can be considered as lost; if the processing time exceeds 26ms, two consecutive frames can be considered as lost, and so on. We can’t tolerate missing five or six frames in a row many times on a page, which means we have to find a way to split up code that takes more than 80ms to execute, which is not an easy task.
When the page is first loaded, it needs to initialize a lot of programs, and there may be a lot of time-consuming DOM operations, so the first 1s of necessary operations will result in a very low frame rate, which we can ignore. Of course, this is for PC, Mobile content is less, no matter DOM or JS script quantity is far less than PC, 1s May be a bit long.
DOMContentLoaded and Load
The DOMContentLoaded event is triggered only when the DOM is loaded and parsed. If the source code output is too much, the client will respond with a longer time to parse the DOM. The parsing time will increase by 50-200ms, which is unnecessary for most pages. The first screen output will be guaranteed, and the subsequent content will only keep the hooks and use JS dynamic rendering.
The Load time can be used to measure the total amount of information received by the client during the first screen loading. If the first screen is full of large-size pictures or the client establishes connections with the back end for many times, the Load time will be prolonged accordingly.
fluency
Fluency is visual feedback on FPS, the higher the FPS, the smoother the visual presentation. In order to ensure page loading speed, many contents will not be fully loaded to the client when the page is opened. The smoothness mentioned here is a visual buffer for waiting, as shown below in a rendering of the Google Plus page:
Taobao home page performance optimization
Due to platform limitations, taobao’s home page faces a congenital performance defect. Rendering of the first screen requires data from 7 different back ends, which is difficult to combine. If the user’s screen is large, the area of the first screen is also large, and the corresponding data interface of the back end platform is more. The data is personalized content or advertising content, so requests cannot be cached.
Priority of key modules
No matter how large the area of the user’s first screen is, ensure that key modules are loaded first. The following code snippet is the core of initializing all modules:
$('.J_Module').each(function(mod) {
var $mod = $(mod);
var name = $mod.attr('tms');
var data = $mod.attr('tms-data');
if($mod.hasClass('tb-pass')) {
Reporter.send({
msg: "Skip modules" + name
});
return; } // Ensure that the first screen module is loaded firstif (/promo|tmall|tanx|notice|member/.test(name)) {
window.requestNextAnimationFrame(function(){// The last parameter is Force, Force rendering, not lazy load processing new Loader()$mod, data, /tanx/.test(name));
});
} else{// The rest of the modules enter the lazy load queue lazyqueue.push ({$mod: $mod, data: data, force: /fixedtool|decorations|bubble/.test(name) }); }});Copy the code
TMS output modules will contain a.j_module hook and will preload JS and CSS files.
For modules without JS content, the system will mark tB-pass in advance and skip this module during initialization. For key modules on the first screen, lazy loading monitoring will be directly entered:
// $box// New Loader($box, data) ->
datalazyload.addCallback($box.function() {
self.loadModule($box, data);
});
// $boxRender immediately // new Loader($box, data, true) ->
self.loadModule($box, data);
Copy the code
In addition to modules that must be loaded immediately, key modules are added to the lazy loading monitor because there is no need to render these front-screen modules when some users enter the page and drag the page down quickly.
Non-critical modules are uniformly sent to lazyQueue, not based on adding non-critical modules to lazy load monitoring, for two reasons:
- Once monitoring is added, the program scroll needs to make calculation judgment for each module. There are too many modules, there may be a performance loss
- If the key module is not loaded, the non-key module will enter the window and start rendering, which will affect the key module rendering
So, when do you start loading non-critical modules
var __lazyLoaded = false;
function runLazyQueue() {
if(__lazyLoaded) {
return;
}
__lazyLoaded = true;
$(window).detach("mousemove scroll mousedown touchstart touchmove keydown resize onload", runLazyQueue);
var module;
while (module = lazyQueue.shift()) {
~function(m) {/ / that the browser idle time to deal with JS, guarantee the congestion window. RequestNextAnimationFrame (function() {
new Loader(m.$mod, m.data, m.force);
});
}(module);
}
}
$(window).on("mousemove scroll mousedown touchstart touchmove keydown resize onload", runLazyQueue); / / worry not trigger the onload event, after the 5 s implement lazy loading queue window. RequestNextAnimationFrame (function() {
runLazyQueue();
}, 5E3);
Copy the code
The code above should be clear enough to start adding non-critical modules to lazy load monitoring under two requests:
- When mousemove Scroll mousedown TouchStart TouchMove KeyDown Resize onload is triggered, the user starts to interact with the page and the program must be loaded.
- If the user is not interacting, but the page is already onloaded, the application should not waste this golden opportunity to load content. After testing, in some cases, the onload event did not trigger (for unknown reasons), so a timeout load was set. After 5s, the rest of the non-critical modules were added to the lazy load monitoring regardless of the page loading status.
Lazy execution, there is interaction to execute
If the above optimization is called lazy loading, this optimization can be called lazy execution.
Cover page containing several modules are interaction, such as big area TAB, convenient service floating layer and the theme of the supernatant of the market, part of the user to enter the page may not use these features, so the program does not do to these modules on the complete initialization, but wait until the user hover on the module to execute all logic.
Lazier execution, refresh the page to execute
There are two secondary requests in the first screen. One is the hot label of the subject market, marking the three categories that users browse most frequently. The second is the background of the personal center. Different cities will display different background pictures, and the city information needs to be requested here.
In both cases, the rendering strategy is to make a request during the idle period of the program, or after window.onload 10 seconds, and then cache the result of the request locally so that the user can see the effect when he/she visits taobao’s home page the second time. This is a lazier implementation where the user refreshes the page to see it. This optimization is acceptable to the product, but also technically reasonable optimization means.
Picture size control and lazy loading
No matter the source of the image link is operation filling or interface output, it is difficult to ensure that the image has the proper width and height. In addition, with the increasing number of Retina screens nowadays, it is not easy to process the image to provide high-quality visual experience for such users.
<img src='//g.alicdn.com/s.gif' data-src='//g.alicdn.com/real/path/to/img.png' />
Copy the code
Ali CDN supports image size compression, as shown in the picture of 200×200:
$img = '//g.alicdn.com/real/path/to/img.png_400x400.jpg';
<img src='{{$img}}_100x100jpg_.webp' />
Copy the code
In this case, the picture will not be displayed correctly. The home page of all pictures lazy loading have done a unified function processing:
src = src.replace(/\s/g, ' ');
var arr;
if(/(_\d{2,}x\d{2,}\w*? \. (? :jpg|png)){2,}/.test(src) && src.indexOf('_!!!!! ') == -1) {
arr = src.split('_');
if (arr[arr.length - 1] == '.webp') {
src = [arr[0], arr[arr.length - 2], arr[arr.length - 1]].join('_');
} else {
src = [arr[0], arr[arr.length - 1]].join('_'); }}if (src.indexOf('_!!!!! ') > -1) { src = src.replace(/((_\d{2,}x\d{2,}[\w\d]*? |_co0)\.(jpg|png))+/,'$1');
}
WebP.isSupport(function(isSupportWebp) {// HTTPS protocol access problems IE8, go to schemaif(/^http:/.test(src)) { src = src.slice(5); } // Support webP format, and host ends with taobaocDN and alicdn, and not s.goif imageif (isSupportWebp && /(taobaocdn|alicdn)\.com/.test(src) && (src.indexOf('.jpg') ||
src.indexOf('.png')) &&! /webp/.test(src) && ! ignoreWebP && ! /\/s\.gif$/.test(src)) { src +='_.webp';
}
$img.attr('src', src);
});
Copy the code
Module to hook, go configuration
The TMS module outputs the data id on the hook:
If the module is asynchronous display, you can find module data through TMS-datakey, and the individuation of the home page is selected from dozens of hundreds of modules through the algorithm, if all these module hooks output, although the data is convenient, but there is a lot of redundancy, this optimization strategy is: Separate the modules with the same data format and create a new page as the data page. So you can see several pieces of configuration information like this in the source code:
<textarea class="tb-hide"> [{"backup":"false"."baseid":"1"."mid":"222726"."name":"iFashion"."per":"false"."tid":"3"."uid":"1000"}, {"backup":"false"."baseid":"3"."mid":"222728"."name":"Beauty show"."per":"false"."tid":"3"."uid":"1001"}, {"backup":"false"."baseid":"4"."mid":"222729"."name":"Love to shop"."per":"false"."tid":"4"."uid":"1002"}, {"backup":"false"."baseid":"2"."mid":"222727"."name":"Global buy"."per":"false"."tid":"4"."uid":"1003"}]</textarea>
Copy the code
Reduced the amount of source code and DOM parsing.
Low frequency modification module, cache requests
Some module data is rarely modified, such as the bottom of the interface data, Ali APP module data, etc., you can adjust the parameters to set the cache time of the module, such as:
io({
url: URL,
dataType: 'jsonp',
cache: true,
jsonpCallback: 'jsonp' + Math.floor(new Date / (1000 * 60)),
success: function() {/ /... }});Copy the code
Math.floor(new Date/(1000 * 60)) this value does not change for a minute, that is, the request is cached locally for a minute, for low frequency modification modules, the cache time can be set to a day, that is:
Math.floor(new Date / (1000 * 60 * 60 * 24))
Copy the code
Of course, we can also cache the module data locally:
offline.setItem('cache-moduleName', JSON.stringify(data), 1000 * 60 * 60 * 24);
Copy the code
The cache expiration time is set to 1 day. Taobao’s home page mainly adopts local cache.
Use the slow effect to reduce the anxiety of waiting
This aspect of optimization is not a lot, but there is a little effect, many modules are not dry.show(), but through animation effect, slow presentation, this aspect of optimization is recommended to use CSS3 attribute to control, performance consumption will be much less.
Optimization thinking Angle
There are many entry points for page optimization, and we may not be able to cover all of them, but for a page carrying a large amount of traffic, the following must be implemented effectively:
- The first screen must be fast
- Scrolling must be smooth
- Don’t load what you can’t load
- Don’t execute what you can’t
- Gradual display, smooth display
Of course, performance optimization is not limited to the above aspects. In comparison with Chrome Timeline bar and line chart, we can also find many optimization points, such as:
- There was a painting block around 1.0s, probably due to the large size of the module being shown at once
- As you can see from the FPS bar chart, there are several Render and JavaScript frame drops between 1.5s and 2.0s
- The extra red dot shows the page jank count and can also locate the code stack
During optimization, you need to think more about how to batch the blocking scripts and how to evenly distribute the long-running scripts on the timeline. These optimizations are reflected in the details of the code, the macro processing is difficult to have a significant effect. Of course, in the macro, Taobao home page also has an obvious optimization:
// https://gist.github.com/miksago/3035015#file-raf-js
(function() {
var lastTime = 0;
var vendors = ['ms'.'moz'.'webkit'.'o'];
for(var x = 0; x < vendors.length && ! window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if(! window.requestAnimationFrame) { window.requestAnimationFrame =function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if(! window.cancelAnimationFrame) { window.cancelAnimationFrame =function(id) {
clearTimeout(id);
};
}
})();
Copy the code
This code basically ensures that each module is initialized during the browser idle period, reducing unnecessary frame loss. This optimization can also be applied to the detailed code of each module, but the optimization is more difficult.
summary
Optimizing the performance of your code is a delicate task, and if you want to optimize the performance of a large, unoptimized page, you may face a refactoring of your code. This paper starts from the problems of taobao home page personalization, tells the page optimization practice from micro to macro, and puts forward several optimization standards that can be used for reference, hoping to inspire you. The description of the optimization details is not perfect or comprehensive enough, but they are all worthy of optimization.
Address: reprinted fed.taobao.org/blog/2016/0…