提高浏览器并发
我们可以对个别URL的域名分散处理,比如我们的图片域名,一般用类似img.guoweiwei.com的域名,当一个页面包含20多张图片的时侯,那起码有10几个恳求会被抵挡,而假如我们分散到不同域名的时侯,至少这20个图片恳求会并发进行,网站打开速率会显著提高好多。类似的,可以对一些css/js的域名同样处理。
服务器端响应使用流业务插口内部聚合防止代码问题页面解析和处理关键渲染路径(CRP)
CRP就是首屏渲染优化,可以从以下方向出发(包含但除了限于):
减少网路发送的数据量
采用精简(移除注释,空格)、混淆(额外减短变量名)的方法
gzip压缩,现在绝大部分浏览器都支持gzip压缩
部分资源可考虑采用内联
静态资源采用浏览器缓存,时间要长
删除无用的代码
减少关键资源的数目,移除非关键渲染资源
css默认会生成cssom。通过非关键资源拆下来,单独外联引入,增加media,则浏览器只会下载,不会解析(用到的时侯解析)。但是此时额外降低了网路恳求,需要权衡
js执行会等待cssom建立完毕,并且会阻塞dom的重构。动态引入js
减少阻塞解析的js
异步加载 async
defer、脚本放在最顶部
参考文献:关键渲染路径、以浅显的方法理解关键渲染路径
避免 404防止小型复杂的布局
大型复杂的布局伴随着须要布局的元素数目好多、布局的复杂性很高,当修改款式时,浏览器会检测任何修改是否须要估算布局,以及是否须要更新渲染树。对“几何属性”(如长度、高度、左侧或底部)的修改都须要布局估算。布局几乎总是作用到整个文档。如果有大量元素,将须要很长时间来算出所有元素的位置和规格。
使用 flexbox 而不是较早的布局模型
flexbox的布局形式在渲染时 要比float、定位等手段布局的时间更短,渲染速率更快
参考文献:前端优化之六:避免小型、复杂的布局和布局晃动
渲染层合并
合成层用处:
提升动漫疗效
减少勾画区域
合理管理合成层
合成层的方式:will-change 设置为 opacity、transform、top、left、bottom、right 可以将元素提高为合成层。
对于这些目前还不支持 will-change 属性的浏览器,目前常用的是使用一个 3D transform 属性来强制提高为合成层。
页面渲染及运行时防止强制同步布局
首先是执行JavaScript脚本,然后是款式估算,然后是布局。但是,我们还可以强制浏览器在执行JavaScript脚本之前先执行布局过程,这就是所谓的强制同步布局。
避免代码出现在不合适的位置
批量化操作(批量读取元素款式属性)
还有一些更为严重的情况,例如在循环中不断触发强制同步布局(又叫晃动布局),对此我们可以如下:
var width = box.offsetWidth;
function resizeAllParagraphsToMatchBlockWidth() {
for (var i = 0; i < paragraphs.length; i++) {
// Now write.
paragraphs[i].style.width = width + 'px';
}
}
如果是协程不断的触发 我们可以使用RAF(requestAnimationFrame)API
window.requestAnimationFrame(() => {
var $ele = document.getElementById('main');
var height = $ele.offsetHeight;
// ……
});
长列表优化使用Virtual List机制
它可以保证在列表元素不断降低,或者列表元素好多的情况下,依然拥有挺好的滚动、浏览性能。它的核心思想在于:只渲染可见区域附近的列表元素。大致思路:
监听页面滚动或则其他造成图层变化的风波
滚动时按照滚动的距离估算须要展示的列表项
将列表项中展示的数据与组件替换成当前须要展示的内容
修改偏移量到对应的位置
实现原生Virual Scroller
virtual-scroller(一个html标签)是未来 Web 平台的一个潜在特点,是layered API 项目的一部分,用于将 JavaScript 对象集映射到 DOM 节点上,并且只渲染当前可见的 DOM 节点,其余部份为“虚拟”的。在 feed 流、图片库等好多场景下十分有用
import "std:virtual-scroller";
item 1
item 2
item 3
item 4……
item 1000
参考文献:Web 长列表的救星?谷歌推出 Virtual Scroller、前端虚拟列表的实现、如何不择手段提高scroll风波的性能
避免JS占用时间过长
由于渲染线程和 JavaScript 线程之间互斥,所以 JavaScript 执行占用时间过长会导致未能及时渲染,可以通过如下方式进行优化:
任务分解
错误示范:
document.body.innerHTML = '';
for(var i = 0; i < 1e5; i++) {console.log(1+1)}
正确示范:
document.body.innerHTML = '';
let step = 0;
function subtask() {
if (step === 1e5) {
return;
}
window.requestAnimationFrame(function () {
for(var i = 0; i < 1e4; i++) {step++; console.log(1+1)}
subtask();
});
}
subtask();
我们把 10万次分散为十个 1万次的子任务,虽然同样执行了 10万次估算,但是页面迅速被清空了。2. 延迟执行
并行估算( Web Worker)
// index.js
const worker = new Worker('worker.js');
worker.addEventListener('message', function (e) {
console.log(`result is ${e.data}`);
}, false);
worker.postMessage('start');
// worker.js
self.addEventListener('message', function (e) {
if (e.data === 'start') {
// 一些密集的计算……
self.postMessage(result);
}
}, false);
参考文献:JS运行机制、优化js脚本设计,防止浏览器假死、加快javascript代码运行 —— 避免长时间运行
减少不必要的重定向
当页面发生了重定向,就会延后整个HTML文档的传输。在HTML文档抵达之前,页面中不会呈现任何东西,也没有任何组件会被下载。所以一些不是必要的重定向尽可能的降低
DOM优化降低DOM数目
在HTML生成DOM树的时侯,DOM数目越少,HTML渲染速率越快
减少DOM操作
每次操作DOM,都会带来repaint和refolw
批量处理DOM操作:
将元素移除DOM Tree,修改完后再放回来,因此只会调用一次repaint或则reflow
批量更改款式
改变classname,或者用css(),原理和批量处理js一样
尽量不要使用tabel布局
tabel中某个元素改变了,整个tabel都会reflow.如果非用不可,可以设置tabel-layout:auto或则tabel-layout:fixed,让tabel一行一行的渲染,限制渲染范围
尽量不要使用css表达式
每估算一次才会触发reflow一次
string用链表join联接
在js中使用“+”来拼接字符串效率比较低,因为每次运行就会开辟新的显存并生成新的字符串变量,然后将拼接的字符串形参给新变量。使用链表的话效率就高一点
css选择符优化
因为css是从右向左解析的,根据这个规则,尽量使左侧的款式惟一
事件代理/事件委托
事件管理的函数变少了
添加和更改元素时侯可以不需要由于元素的改动而更改风波绑定
JS和DOM节点之间的关联变少了,减少\因循环引用而带来的内存泄漏发生的几率。
页面初始化时侯不会由于没有加载dom造成前面虽然添加了dom,事件也不生效
参考文献:简述JS中的风波委托和事件代理
防抖和节流防抖
当持续触发风波时,一直到设定风波触发时间的时间段都没有再度操作时侯,才会触发风波,应用场景:模糊查询,根据输入内容提示相关完整内容
// 防抖
function debounce(fn, wait) {
var timeout = null;
return function() {
if(timeout !== null) clearTimeout(timeout);
timeout = setTimeout(fn, wait);
}
}
// 处理函数
function handle2() {
console.log("防抖函数");
}
// 滚动事件
window.addEventListener('scroll', debounce(handle2, 1000));
节流
当持续触发风波时,保证一定时间段内只调用一次事件处理函数。应用场景:节流、防止短时间多次递交操作
var throttle = function(func, delay) {
var timer = null;
return function() {
var context = this;
var args = arguments;
if (!timer) {
timer = setTimeout(function() {
func.apply(context, args);
timer = null;
}, delay);
}
}
}
let func = function() {
console.log("节流函数");
}
window.addEventListener('scroll', throttle(func, 1000));
tips:节流和对焦应用较为广泛,以上应用场景仅是作为示例,具体场景依据业务需求确定,主要解决的问题是:事件处理函数调用的频度无限制,会加重浏览器的负担或则后台交互多次触发等问题造成的用户体验十分糟糕。
及时回收显存/垃圾搜集(内存泄漏知识点)
常见内存泄漏的情况:
DOM/BOM 对象泄露从外到内执行appendChild。这时虽然调用removeChild也未能释放
var parentDiv = document.createElement("div");
var childDiv = document.createElement("div");
document.body.appendChild(parentDiv);
parentDiv.appendChild(childDiv);
解决办法:从内到外执行appendChild
给DOM对象添加的属性是一个对象的引用
var testObject = {};
document.getElementById('idname').property = testObject;
解决办法:
window.onunload=function(){
document.getElementById('idname').property = null; //释放内存
};
DOM对象与JS对象互相引用
function testObject(element) {
this.elementReference = element; // 为testObject(js)对象的属性绑定element(DOM)对象
element.property = this; // 为element(DOM)对象的属性绑定testObject(js)对象
}
new testObject(document.getElementById('idname'));
解决办法:
document.getElementById('idname').property = null;
script 中存在对DOM/BOM 对象的引用造成Javascript 对象泄露意外的全局变量
function foo(arg) {
bar = "aaaaa";
}
实际上等价于
function foo(arg) {
window.bar = "aaaaa";
}
解决办法:为了避免这些错误的发生,可以在你的 JavaScript 文件开头添加 'use strict'; 语句
定时器setTimeout setInterval
当不需要setInterval或则setTimeout时,定时器没有被clear,定时器的回调函数以及内部依赖的变量都不能被回收,造成内存泄漏。比如:vue使用了定时器,需要在beforeDestroy中做对应销毁处理。js也是一样的。
如果在mounted/created 钩子中使用了off)处理死循环或则大量重画一个属性一般由闭包引起,比如风波处理反弹,导致DOM对象和脚本中对象单向引用,这个时常见的泄露缘由
function fn1(){
var n=1;
function fn2(){//在加一个fn2当他的子集
alert(n);
}
return fn2();
//return出来后 他就给 window了所以一直存在内存中。因为一直在内存中,在IE里容易造成内存泄漏
}
fn1();
解决办法 :尽量书写的时侯,避免这些情况。
性能更好的API
选择器:优先级 id>class>元素>相邻选择器>子选择器>后代选择器>通配符选择器>属性选择器>伪类选择器
requestAnimationFrame来代替setTimeout和setInterval
使用IntersectionObserver来实现图片可视区域的懒加载
使用web worker
参考文献:前端干货知识—性能更好的API
加快解析以及渲染树建立
包含 但除了限于:
简化选择器
避免使用花费性能过多的属性 如:border-radius、box-shadow、opacity、transform、filter、position: fixed等
使用先进的布局形式,如flex
也包括如静态资源优化、cdn分发、页面渲染性能的优化等,在其他模块有描述,这里不再赘言
参考文献:前端阶段性总结(二):页面渲染机制与性能优化、浏览器的工作原理:新式网络浏览器幕后起底
reflow/repaint
repatint:重绘是指css样式的改变,但元素的大小和规格不变,而造成节点的重新勾画。任何对元素款式,如background-color、border-color、visibility 等属性的改变。css 和 js 都可能导致重画。
reflow : 回流(reflow)是指元素的大小、位置发生了改变,而造成了布局的变化,从而引起了布局树的重新建立和渲染。回流 触发的情况:1、dom元素的位置和规格大小的变化、2.dom元素的降低和删掉、3.伪类的激活、4.窗口大小的变化、5.增加和删掉class款式、6.动态估算更改css样式;
下面为触发reflow/repaint的详尽style
能触发回流的款式---
width
top
text-align
height
bottom
overflow-y
padding
left
font-weight
margin
right
overflow
display
position
font-family
border-width
float
line-height
border
clear
vertival-align
min-height
white-space
font-size
能触发重画的款式---
color
background
outline-color
border-style
background-image
outline
border-radius
background-position
图片懒加载
图片的懒加载对于其他的文件型懒加载也有一些不同之处,我们可以随着浏览器不断的滚动做对应的懒加载,诸如一些图片博客网站、长列表等的,图片的懒加载核心在于尽量只加载用户正在浏览或则正式会浏览到的图片。实现上来说最简单的就是通过窃听页面滚动,判断图片是否步入视野,从而真正去加载图片。下面是一个图片懒加载的demo
// 加载函数还可以用 Intersection Observer API 这样更简单,但是考虑兼容性最好还是不要用
function loadIfNeeded($img) {
// 获取元素的位置,判断是否进入试图
const bounding = $img.getBoundingClientRect();
if (
// 去掉隐藏图片 提高性能
getComputedStyle($img).display !== 'none'
&& bounding.top <= window.innerHeight
&& bounding.bottom >= 0
) {
// 去掉lazyImg Class 防止重复执行
$img.src = $img.dataset.src;
$img.classList.remove('lazyImg');
}
}
// 这里使用了throttl,可以从上面防抖/节流的模块复制
const lazy = throttle(function () {
// 获取所有lazyimg
const $imgList = document.querySelectorAll('.lazyImg');
// 如果没有需要加载的图片时候移除监听,增加性能
if ($imgList.length === 0) {
document.removeEventListener('scroll', lazy);
window.removeEventListener('resize', lazy);
window.removeEventListener('orientationchange', lazy);
return;
}
// 循环所有需要加载的节点 判断是否需要加载
$imgList.forEach(loadIfNeeded);
}, 200);
window.onload = function(){
// 监听事件
document.addEventListener('scroll', lazy);
window.addEventListener('resize', lazy);
window.addEventListener('orientationchange', lazy);
}
使用方式:img标签src为loading图片(或者基于原图生成的体积小、清晰度低的图片)的地址,当然也可以不要,data-src为图片真实路径,对须要的懒加载的图片降低.lazyImg的class须要注意的:
参考文献:原生js实现图片懒加载(lazyLoad)、js实现图片懒加载原理、IntersectionObserver API 使用教程
页面静态资源优化
页面静态资源优化从整体上来说都是类似的,只有两个目标:
静态资源最小化
静态资源加载怎样更快
基于以上的两个目标,制定出下边几个大方向(包括但不限于):
减少不必要的恳求
减少包体大小
降低应用资源时的消耗
利用缓存
减少不必要的恳求
核心是希望还能降低恳求的数目,因为浏览器对同源恳求有并发上限的限制。请求过多可能会造成恳求被排队了。同时,TCP/IP 的串扰控制也使其传输有慢启动(slow start)的特性,连接刚构建时包体传输速度较低,后续会慢慢提速。因此,发送过多的“小”请求可能也不是一个挺好的做法。减少不必要的恳求主要分为几个方向:
资源优化方向
不需要使用的内容
不恳求
可以延后加载的内容
按需加载
可以合并的资源
资源合并
减少包体大小
包体大小对性能也是有直接影响的。显然同样速度下,包体越小,传输历时越低,整体页面加载与渲染的性能也会更好。减少包体大小主要分为几个方向:
使用适宜当前资源的压缩技术压缩代码
减少包不需要的代码,删除页面无用代码
组件公共化
Tree Shaking(摇树优化,在保证代码运行的前提下,摇掉无用的代码)
降低应用资源时的消耗
有些时侯,浏览器去执行或使用资源的也是有消耗的。例如在 JavaScript 执行了一段 CPU 密集的估算,或者进行频繁的 DOM 操作,这些就会让 JavaScript 的执行弄成影响性能的一大问题。
缓存
缓存的益处不言而喻,能够让资源在最短的时间内加载、解析,缓存在好多时侯会是一个解决性能问题的特别有效的手段。
下面就各类资源的优化进行剖析
JS降低包体大小
主要是通过webpack等工具打包时侯进行一系列优化,进而达到降低包体大小目的,常见的做法如:代码压缩(UglifyJS)、gzip、Tree Shaking等做法,Tree Shaking其本质是通过测量源码中不会被使用到的部份,将其删掉,从而减少代码的容积。来一个事例说明:
// 模块 A
export function add(a, b) {
return a + b;
}
export function minus(a, b) {
return a - b;
}
// 模块 B
import {add} from 'moduleA.js';
console.log(add(1, 2));
可以看见模块B引用了A模块,但是只用了其中的add方式,也就是说打包minus并没有哪些作用,所以完全可以不用打包minus这个方式,可以通过 webpack-bundle-analyzer 这个工具,来查看打包代码上面各个模块的占用大小。
参考文献:webpack tree shaking实现方法
减少不必要的恳求
这个是一个在文档中提了好多遍的点,无外乎下边几点,不再赘言:
代码分拆(code split)与按需加载
代码合并
加快解析和执行
除了js下载须要历时外,脚本的解析与执行也是会消耗时间的。一个 JavaScript 文件,即使内部没有所谓的“立即执行函数”,JavaScript 引擎也是须要对其进行解析和编译的。甚至有时候加载同样字节数的js对性能的影响可能会低于图片,因为图片的处理可以置于其他线程中并行执行,所以换一个角度来说,删除不必要的代码,对于页面打开速率也是有用处的,对于一些单页应用,在加载完核心的 JavaScript 资源后,可能会须要执行大量的逻辑。如果处理不好,可能会出现JavaScript线程长时间执行而阻塞主线程的情况。
缓存
缓存早已说过好多,这里扩充一下
如何降低 webpack 编译不当带来的缓存失效的方案:
使用 Hash 来代替自增 ID
将 runtime chunk 单独分拆下来
使用 records
参考文献:浅谈Webpack 持久化缓存实践
CSS关键渲染路径优化
在性能优化上,其实我们会更关注关键渲染路径(CRP 指优先显示与当前用户操作有关的内容一般就是首屏),而不一定是最快加载完整个页面。做法就是将关键CSS的内容通过 标签内联到 中,然后异步加载其他非关键CSS。这样对于关键路径的渲染可以降低一次 RTT (Round-Trip Time)。用户可以更快听到一些页面初始的渲染结果。
优化资源恳求
与 JavaScript 类似,我们的 CSS 也是可以按需加载的。
按需加载
合并文件(减少恳求数)
请求的优先级排序(根据文件重要性进行恳求排序)在响应式的页面中,可能涉及media,即在可能在400px的页面下只须要max400.css,而不需要max500.css,针对这个问题,link 标签上虽然有一个 media 属性来处理媒体查询下的加载优先级。浏览器会优先下载匹配当前环境的款式资源,相对的,其他非匹配的优先级会增长
这样分拆后,当页面小于400px时,max500.css 的优先级会增加,注:只是增加并非不加载
慎用 @importCSS 提供了一个 @import 语法来加载外部的款式文件。这样浏览器只有当下载了 index.css 并解析到其中 @import 时,才会再去恳求 other.css。
谨慎对待js脚本文件位置
减少包体大小
老生长谈了,和js差不多
压缩(uglifycss)
gzip
选择合适的兼容性polyfill支持,避免过分繁杂perfixer。
缓存(webpack MiniCssExtractPlugin)Image优化恳求
优化恳求和css、js一样,尽可能的合并文件,针对图片又有所不同,即我们不可能将所有的图片全部可病到一起,这样不但不是优化,而是自取灭亡,那么如何优化恳求呢?我们可以做的是将一些大型icon合并成为雪碧图,雪碧图的核心原理在于设置不同的背景偏移量,来展示大图中对应的图标部份。
减少图片大小针对通常图片我们减小图片的形式大多数是在文件本身进行一些操作,在制做图片时侯尽量尽可能降低视口、选择合适的大小/分辨率,在保存图片时侯尽可能压缩图片质量,一般来说80以上是完全没有问题的,甚至在60-80也不会有哪些影响,在图片格式上,我们尽量选定如:webp、svg、jpg,有一些须要使用手机或则单反拍下来的图片我们应当删掉图片多余的信息。webpack中可以使用image-webpack-loader进行压缩
使用base64严格来说这点应当属于优化恳求下边,主要应用于一些比较重要的地方(首屏或则一些icon),因为当浏览器解析时侯遇见base64图片就不会在发起恳求,而是直接解析 base64 字符串,但是并不建议整个页面全部都使用base64进行处理,因为这些方法图片容积会减小三分之一,并且不利于复用独立的文件缓存。
缓存
图片也是可以缓存的。
Font使用font-display实现fout(不是很建议,因为这是一个新属性,可能会有兼容问题)
支持的浏览器
在说这个之前先解释下哪些是fout?
FOUT:在字体加载过程中使用默认的系统字体,字体加载完后显示加载的字体,如果超过了FOIT(3s)字体还没加载,则继续使用默认的系统字体。
在@font-face中设置 font-display: swap,他可以让FOIT的默认行为变为FOUT
@font-face {
font-family: 'Samplefont';
src: url(/static/samplefont.woff2) format('woff2'),
url(/static/samplefont.woff) format('woff');
font-display: swap;
}
使用内联字体
和image,base64差不多,我们可以将字体文件转为base64的字符串,设置到@font-face里的src属性上。
使用CSS Font Loading API(同样有兼容性问题,并且很严重,只作为一个未来可能使用的优化)
支持的浏览器
参考文献:深入理解CSS @font-face性能优化、字体加载策略大全、CSS @font-face性能优化
Video
视频作为一种重要的媒体形态,在网站中使用可以增强网站内容的丰富性,但同时对网路加载来说也是一个负担。所以会出现一些如下针对视频的优化。大部分和image差不多,但也有一些区别
使用合适的视频格式
不同的视频编码格式,其数据大小也大都不同。目前在HTML5 Video中常用的格式为MPEG-4。除了MPEG-4之外,还支持一种叫WebM的新的视频格式,不过相对的兼容性较差,不过没关系,我们可以用多个。
视频压缩
和图片一样视频也有压缩,视频压缩工具推荐HandBrake、Freemake、Hybrid;
移除不必要的音轨信息
在个别特定场景下,本身就是不需要声音的,所以可以将video标签设置为muted
Your browser does not support the video tag.
使用“流”
尝试让浏览器使用“流”或者小分片的方法来播放你的视频,例如常用的 HLS (HTTP Live Streaming) 技术。简单来说,使用 HLS 技术,你的视频会包含一个 .m3u8 的索引文件和一系列包含播放内容的 .ts 分片。浏览器通过不断下载一小段的分片来进行视频播放,避免了完整视频下载的流量消耗。
参考文献:前端获取视频流并播放
静态资源缓存参考文献:webpack实现静态资源缓存的那点事
预加载预加载技术
在webpack中使用预恳求
预加载可以配合 code split 来使用,可以在减少初始加载量的情况下,尽量保证按需加载时的体验
// prefetch
import(/* webpackPrefetch: true */ './sub1.js');
// preload
import(/* webpackPreload: true */ './sub2.js')
参考文献:前端优化——预加载篇、在webpack中使用prefetch/preload、使用Resource Hint提高页面加载性能与体验
视频预加载preload
video preload参数
值作用
none
不载入视频(即不预加载)
meta
载入元数据(时长、尺寸、文字轨道)
auto
加载整个视频
preload link
video.src = 'https://cdn.com/small-file.mp4';
video.play().then(_ => {
});
自定义buffer
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen, { once: true });
function sourceOpen() {
URL.revokeObjectURL(video.src);
const sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp09.00.10.08"');
// Fetch beginning of the video by setting the Range HTTP request header.
fetch('file.webm', { headers: { range: 'bytes=0-567139' } })
.then(response => response.arrayBuffer())
.then(data => {
sourceBuffer.appendBuffer(data);
sourceBuffer.addEventListener('updateend', updateEnd, { once: true });
});
}
function updateEnd() {
// Video is now ready to play!
var bufferedSeconds = video.buffered.end(0) - video.buffered.start(0);
console.log(bufferedSeconds + ' seconds of video are ready to play!');
// Fetch the next segment of video when user starts playing the video.
video.addEventListener('playing', fetchNextSegment, { once: true });
}
function fetchNextSegment() {
fetch('file.webm', { headers: { range: 'bytes=567140-1196488' } })
.then(response => response.arrayBuffer())
.then(data => {
const sourceBuffer = mediaSource.sourceBuffers[0];
sourceBuffer.appendBuffer(data);
// TODO: Fetch further segment and append it.
});
}
参考文献:Fast Playback with Video Preload、preload
其他打包组件成复合文本
把页面内容打包成复合文本就仿佛带有多附件的Email,它还能使你在一个HTTP请求中取得多个组件
减少iframe
iframe 中的文件须要单独恳求,这就意味着假如页面a中有一个jqury,a通过iframe使用了页面b,而b中也使用了jquery 则会恳求两次jquery。并且iframes会阻塞页面加载
有人可能希望 iframe 会有自己独立的连接池,但不是这样的。绝大部分浏览器,主页面和其中的 iframe 是共享那些联接的。这意味着 iframe 在加载资源时可能用光了所有的可用联接,从而阻塞了主页面资源的加载。如果 iframe 中的内容比主页面的内容更重要,这其实是挺好的。但一般情况下,iframe 里的内容是没有主页面的内容重要的。这时 iframe 中用光了可用的联接就是不值得的了。一种解决办法是,在主页面上重要的元素加载完毕后,再动态设置 iframe 的 SRC。
避免空的src
参考文献 :为什么后端要防止空的src
CSS 放到底部,JS 放到顶部favicon.ico要小并且可缓存降低flash其他更多优化ing