在chrome浏览器,对于同一域名,最多支持6个请求的并发,其他请求会推入到队列中等待或停滞不前,直到6个请求之一完成后,队列中新的请求才会放出。
可以看到,六个绿色条并发请求,四个灰色条等待请求,最下面三个绿色条3.4s后才触发请求
- html、css、js 代码压缩
- 公共文件(js/css)合并、请求合并
- 浏览器缓存(强缓存、弱缓存)
- CDN(Content Delivery Network,内容分发网络)加速。通过将静态资源(例如javascript,css,图片等等)缓存到离用户很近的相同网络运营商的CDN节点上,不但能提升用户的访问速度,还能节省服务器的带宽消耗,降低负载(因此,一个地区内只要有一个用户先加载资源,在 CDN 中建立了缓存,该地区的其他后续用户都能因此而受益)
- loading 动画
- 页面骨架屏
- 减少操作 dom 方法
- 优化图片加载
- 懒加载和预加载
减少操作 dom 方法
- 插入大量dom元素时,可以使用innerHTML替代逐个构建元素
- 处理列表子元素的事件时,可以使用事件委托
优化图片的加载
1. 图片懒加载,优先加载浏览器可视区域的图片
先将img标签的src链接设为同一张图片(比如空白图片),然后给img标签设置自定义属性(比如data-src),然后将真正的图片地址存储在data-src中,当JS监听到该图片元素进入可视窗口时,将自定义属性中的地址存储到src属性中。达到懒加载的效果。
这样做能防止页面一次性向服务器发送大量请求,导致服务器响应页面卡顿崩溃等。
<style>
.container {
max-width: 800px;
margin: 0 auto;
}
.container:after {
content: "";
display: block;
clear: both;
}
.container img {
width: 50%;
height: 260px;
float: left;
}
</style>
<body>
<div class="container">
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img4.imgtn.bdimg.com/it/u=951914923,777131061&fm=26&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img1.imgtn.bdimg.com/it/u=637435809,3242058940&fm=26&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img1.imgtn.bdimg.com/it/u=3990342075,2367006974&fm=200&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img1.imgtn.bdimg.com/it/u=1813891576,1754763093&fm=26&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img4.imgtn.bdimg.com/it/u=2539922263,2810970709&fm=200&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img4.imgtn.bdimg.com/it/u=1878067600,3935137756&fm=200&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img3.imgtn.bdimg.com/it/u=85690711,3884201894&fm=26&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img2.imgtn.bdimg.com/it/u=3844233833,3942617167&fm=200&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img0.imgtn.bdimg.com/it/u=1846695025,2515725663&fm=26&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img3.imgtn.bdimg.com/it/u=346230831,1833217134&fm=200&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img5.imgtn.bdimg.com/it/u=3478148120,2683867435&fm=26&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img5.imgtn.bdimg.com/it/u=2298824648,1812234339&fm=200&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img2.imgtn.bdimg.com/it/u=4201594846,4178139206&fm=26&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img2.imgtn.bdimg.com/it/u=484389598,819397330&fm=200&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img1.imgtn.bdimg.com/it/u=3729466012,914166979&fm=26&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img2.imgtn.bdimg.com/it/u=354463615,3836278171&fm=200&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img5.imgtn.bdimg.com/it/u=1831250492,3489827059&fm=200&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img1.imgtn.bdimg.com/it/u=779005622,2247570143&fm=200&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img1.imgtn.bdimg.com/it/u=1968229118,3512711019&fm=26&gp=0.jpg" />
<img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1"
data-src="http://img2.imgtn.bdimg.com/it/u=1088428253,1150170159&fm=200&gp=0.jpg" />
</div>
</body>
</html>
<body>
<script>
// 一开始没有滚动的时候,出现在视窗中的图片也会加载
start();
// 当页面开始滚动的时候,遍历图片,如果图片出现在视窗中,就加载图片
var clock; //函数节流
$(window).on("scroll", function () {
if (clock) {
clearTimeout(clock);
}
clock = setTimeout(function () {
start();
}, 200);
});
function start() {
$(".container img")
.not("[data-isLoading]")
.each(function () {
if (isShow($(this))) {
loadImg($(this));
}
});
}
// 判断图片是否出现在视窗的函数
function isShow($node) {
return $node.offset().top <= $(window).height() + $(window).scrollTop();
}
// 加载图片的函数,就是把自定义属性data-src 存储的真正的图片地址,赋值给src
function loadImg($img) {
$img.attr("src", $img.attr("data-src"));
// 已经加载的图片,我给它设置一个属性,值为1,作为标识
// 弄这个的初衷是因为,每次滚动的时候,所有的图片都会遍历一遍,这样有点浪费,所以做个标识,滚动的时候只遍历哪些还没有加载的图片
$img.attr("data-isLoading", 1);
}
</script>
2. 小图片或图标,可用SVG、Iconfont、Base64等技术,多个图标也可以制作成雪碧图(CssSprites)
3. 加载时预先加载一张特别小的通用略缩图,正式图片加载完成后替换略缩图
4. 服务端根据业务需要可以对图片进行压缩 (不影响用户体验的情况下)
5. 为项目添加骨架屏
6. Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。可查看RFC2045~RFC2049,上面有MIME的详细规范。
- 图片的 base64 编码就是可以将一幅图片的二进制编码成一串字符串,使用该字符串代替图像地址
- 可以减少http请求,base64可以随着html的下载同时下载
- 适用于小图片和简单图片
预加载
- 纯 css 实现预加载
不在浏览器可视范围内加载图片,直接 css 加载,
但图片会随文档一起加载,此时可能会降低文档的加载速度 - 纯 js 实现预加载
js 脚本提前加载图片 src 或使用 image 对象提前加载图片 - css 和 js 实现预加载
如 img 标签最初设置为 display: none,要加载的时候显示
或者滚动条到达可视范围内,js 为目标 div 加上这个已经加载好的 css 属性 - ajax 预加载
提前 ajax 请求获取数据
场景有个 tab 标签页,当鼠标放到某个 tab,立刻 ajax 加载该 tab 的数据
当点击这个 tab 标签页的时候,就可以立刻加载出来,再将数据缓存起来或加入全局变量,下一次使用直接从缓存读取
节点
element.parentNode 返回元素的父节点
element.childNodes 返回元素的一个子节点的数组
element.nodeName 返回元素的标记名(大写),用的时候转换小写(element.nodeName.toLowerCase())
event.target:返回触发此事件的元素(事件的目标节点)
详看:https://www.cnblogs.com/ainyi/p/8794159.html
HTML DOM 元素对象:http://www.runoob.com/jsref/dom-obj-all.html
HTML DOM 事件对象:http://www.runoob.com/jsref/dom-obj-event.html
工作中对于广告编辑页的优化
首先,也是最有效的方法,请说服boss不要在一个页面放太多的广告代码,这样很影响效果和用户体验。
其次,在做了上述工作以后,可以再做一些进一步的优化。根据我的经验,可以有以下几个方面
对于直接嵌入第三方js脚本的,可以直接把对方脚本下载到本地服务器,这样减少了因为第三方脚本响应过慢而影响载入体验。
如果有的脚本广告方要求必须使用他们的脚本地址,你可以使用延迟加载的方法。在document.ready后使用jquery的getScript或者使用LABjs来动态加载js。
对于直接嵌入第三方图片和链接的广告,你可以使用现在已经很成熟的lazyload方案。
用iframe管理广告。这是目前看来比较合理的。
其他优化
- 公共接口合并,减少 http 请求,后端做缓存
- promise all 解决根据请求顺序顺序获取的问题(当前接口的数据展示需要依赖上一个接口数据的情景)旧版本是 若有依赖关系的接口,是等待上一个接口请求完毕,才发送当前接口请求
- 数据预加载(第四个模块的数据默认收起,点击展开的时候预先加载。不用等待)
- 公用数据下沉到领域模型,多个模块复用的数据,不用再次请求接口
实现页面 MVC 结构 可看这里数据处理单独抽出来放在 service 层,(vuex mutation) - 数据处理(数据量很大的时使用数据字典,可以使用 obj.key 得到想要的数据,需要的数据 key 值与数据字段作关系映射)
- 组件化、ESLint 代码规范,便于维护旧版本是 循环使用 if 等于需要的 key 来获取数据
- for 循环的使用,数组循环使用 for of,对象使用 for in
- 路由方面,使用路由懒加载
- 一开始页面需要加载多条请求,在 axios 统一请求拦截加上loading,和接口请求计数器+1,统一响应拦截计数器-1,当等于零就关闭 loading
- 渠道组件和多选省市级三级联动组件的优化(重写 Element 的穿梭框组件)具体看 关于 Element 组件的穿梭框的重构