前言
说到性能优化,我博客前面文章讲了不少,其实性能优化做的好坏,直接体现前端开发人员的水平。因此,很多面试中基本上都会提及这一点。今天主要借鉴淘宝网性能优化方式之一webp及Bigpipe 进行简单的讲解。
webp
打开淘宝网,假如你是chrome浏览器,你会发现,所有图片都是webp结尾的,淘宝网图片运用了webp。假如你是safari浏览器,看到图片就是jpg或者png了,淘宝网自动判断浏览器支持不支持webp,假如支持,则输出相应的图片格式!
看下图:
淘宝网图片请求头。
淘宝网的流程应该也是如下的:
运用了bigpipe客户端服务器端同时渲染,图片全是异步请求。
1、判断浏览器是否支持webp
2、客户端发送请求头到服务器端,假如请求头带:
image/webp,
说明支持webp ,则服务器渲染webp格式图片,否则就是jpg或者png
如何检测平台是否支持webp格式
方法一:
function checkWebp() {
try{
return (document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0);
}catch(err) {
return false;
}
}
console.log(checkWebp()); // true or false
方法二:自官网的。
// check_webp_feature:
// 'feature' can be one of 'lossy', 'lossless', 'alpha' or 'animation'.
// 'callback(feature, result)' will be passed back the detection result (in an asynchronous way!)
function check_webp_feature(feature, callback) {
var kTestImages = {
lossy: "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA",
lossless: "UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==",
alpha: "UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",
animation: "UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"
};
var img = new Image();
img.onload = function () {
var result = (img.width > 0) && (img.height > 0);
callback(feature, result);
};
img.onerror = function () {
callback(feature, false);
};
img.src = "data:image/webp;base64," + kTestImages[feature];
}
其实跟第一种方法差不多,这里提供了几种webp的图片模式,如果浏览器支持webp,那么图片的宽高会大于0,从而返回true,否则返回false.
使用方法:
第一个参数feature可以传 lossy,lossless,alpha,animation中的一个,第一个传个回调函数。获取他result。如果支持,返回ture,否则返回false。可以再谷歌和IE下试试,谷歌返回ture,IE返回false
check_webp_feature('lossless',function(feature,result){
alert(result); //true or false
});
方法三:增加class
;(function(doc) {
// 给html根节点加上webps类名
function addRootTag() {
doc.documentElement.className += "webps";
}
// 判断是否有webps=A这个cookie
if (!/(^|;\s?)webps=A/.test(document.cookie)) {
var image = new Image();
// 图片加载完成时候的操作
image.onload = function() {
// 图片加载成功且宽度为1,那么就代表支持webp了,因为这张base64图是webp格式。如果不支持会触发image.error方法
if (image.width == 1) {
// html根节点添加class,并且埋入cookie
addRootTag();
document.cookie = "webps=A; max-age=31536000; domain=haorooms.com";
}
};
// 一张支持alpha透明度的webp的图片,使用base64编码
image.src = 'data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==';
} else {
addRootTag();
}
}(document));
原理也是一样的,不过这个比较贴近实战,就是加载一张webp图片,如果可以加载出来,那么就是支持webp,否则就是不支持。如果支持webp,那么给html加一个class 叫 webps。
方法四:
var isSupportWebp = !![].map && document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;
一行代码就可以判断浏览器支持不支持webp。
用法:
console.log(isSupportWebp); // true or false
webp格式纯前端应用
这种方式只是纯前端的一种尝试,还是推荐和后端配合使用。
纯前端使用的话,可以如下方式:
在页面加载css之前,加载检测是否支持webp的js。如果支持,则html节点上里面有一名为webps的class。
背景图的话,我们就用写两套。一套是没有用webp的css,一套是用了webp图片的背景图。
.haorooms{
background-image: url('../images/haorooms.jpg');
}
.webps .haorooms{
background-image: url('../images/haorooms.webp');
}
img图片也是一样,用js输出相关路径。特别适用于异步加载。
Bigpipe 技术
也是比较早的前端渲染技术了,淘宝网用了,请看文章:http://taobaofed.org/blog/2016/03/25/seller-bigpipe-coding/
Bigpipe 技术是把网页分割成多个PageLet的小块,然后分段输出到浏览器,前后端并行处理。
BigPipe的原理
BigPipe的主要思想是实现浏览器和服务器的并发执行,实现页面的异步加载,从而提高页面的访问速度。 为了达到这个目的,它首先根据页面的功能或者位置,将页面分成若干个模块,这些模块的名字也被称为PageLet,并对这些分解的模块进行唯一的标识。然后通过Web服务器和浏览器之间建立管道,进行分段输出 (减少请求数)。
下面来看一个简单的例子:
我们来看下面的代码:layout.html
<!DOCTYPE html>
<html>
<head>
<script>
var BigPipe = {
view: function(selector,temp) {
document.querySelector(selector).innerHTML= temp;
}
}
</script>
</head>
<body>
<div id="moduleA"></div>
<div id="moduleB"></div>
<div id="moduleC"></div>
服务端代码,基于express
var express = require('express');
var app = express();
var fs = require('fs');
app.get('/', function (req, res) {
var layoutHtml = fs.readFileSync(__dirname + "/layout.html").toString();
res.write(layoutHtml);
// setTimeout只是模拟异步返回
setTimeout(function() {
res.write('<script>BigPipe.view("#moduleA","moduleA");</script>');
100);
setTimeout(function() {
res.write('<script>BigPipe.view("#moduleC","moduleC");</script>');
},200);
setTimeout(function() {
res.write('<script>BigPipe.view("#moduleB","moduleB");</script>');
res.write('</body></html>');
},300);
res.end();
});
app.listen(3000);
关于Bigpipe,淘宝前端团队有2篇文章,讲的很细致,推荐大家一看:
1、http://taobaofed.org/blog/2016/03/25/seller-bigpipe-coding/