前言
说到性能优化,我博客前面文章讲了不少,其实性能优化做的好坏,直接体现前端开发人员的水平。因此,很多面试中基本上都会提及这一点。今天主要借鉴淘宝网性能优化方式之一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/
2、http://taobaofed.org/blog/2015/12/17/seller-bigpipe/