PHP写的file_merger函数,用来合并压缩多个js或css,减少网站连接请求
[文章作者:磨延城 转载请注明原文出处: https://mo2g.com/view/74/ ]
本篇博客从减少浏览器加载外部资源连接数的思考角度着手,要想深入了解其他加快网页显示速度的原理,估计又得花不少时间,这需要把前端跟后端都说解释清楚.有时间我会分开写其他部分的内容.这里为了节省时间,只介绍如何减少网页需要加载的外部资源,加快浏览器的响应速度.
本篇博客从减少浏览器加载外部资源连接数的思考角度着手,要想深入了解其他加快网页显示速度的原理,估计又得花不少时间,这需要把前端跟后端都说解释清楚。有时间我会分开写其他部分的内容。这里为了节省时间,只介绍如何减少网页需要加载的外部资源,加快浏览器的响应速度。
如果一个页面比较复杂,要展示的内容 比较多,就会包含很多外部资源、css样式还有js脚本,比如某个门户网站的的html代码如下:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>XXX最大的门户网站</title> <!-- 外部css样式资源 开始--> <link type="text/css" rel="stylesheet" href="1.css"/> <link type="text/css" rel="stylesheet" href="2.css"/> ... <link type="text/css" rel="stylesheet" href="n-1.css"/> <link type="text/css" rel="stylesheet" href="n.css"/> <!-- 外部css样式资源 结束--> </head> <body> <!-- 页面展示图片 开始--> <img src="1.jpg"> ... <img src="n.jpg"> <!-- 页面展示图片 结束--> <!-- 外部js脚本资源 开始--> <script scr="1.js"></script> ... <script scr="n.js"></script> <!-- 外部js脚本资源 结束--> </body> </html>
这些大型门户网站一个页面需要加载的外部资源总数,经常超过100个。腾讯QQ首页,就加载高达了192个外部资源。相信这个数字是经过腾讯的前端团队尽了最大努力才压缩下来的结果,如果没做过处理,会怎样?
请看下边的表格,分别显示了各个浏览器在同一时间,能向同一域名请求的最大并发连接数。
浏览器 | HTTP 1.1 | HTTP 1.0 |
IE 6、7、8 | 2~6 | 4~6 |
Firefox | 2~6 | 6~8 |
Safari | 4 | 4 |
Chrome | 4~6 | 4~6 |
如果浏览器支持8个并发链接,每个外部资源加载时间为400ms,那么160个外部资源连接,理论上就需要8000ms(160 ÷ 8 × 400)的加载时间,大约8秒才能显示完整的页面。但实际的情况更加复杂,最基本的问题就是要加载的外部资源数据包的大小,这一因素直接影响了加载时间,要想保证每个外部资源的加载时间为400ms或者更短的时间,这又牵扯到CDN分布式存储。所以,在资金不足的情况下,我们能做的就是减少外部资源的连接数,还有就是精简和压缩静态数据。
为了解决这一问题,我为mPHP核心框架写了一个PHP函数file_merger,用来合并多个CSS样式文件或者JS脚本文件,并对生成的合成文件进行压缩,从而更进一步的减小外部资源的数据大小。
使用环境如下:
测试环境地址:http://localhost/
测试环境目录结构:
/static/css/,css样式目录存在1.css,2.css两个文件
/static/js/,js脚本目录下存在1.js,2.js
/static/merger/,合成文件保存目录
file_merger函数的使用例子如下:
<?php include 'file_merger.php'; $CFG['debug'] = 0;//当值为1的时候,不进行合并压缩,按常规调用 $CFG['java'] = 0;//当值为1的时候,使用yuicompressor压缩;0使用PHP正则表达式简单压缩 $arrCss[] = '1.css'; $arrCss[] = '2.css'; $arrJs[] = '1.js'; $arrJs[] = '2.js'; $css = file_merger($arrCss,'main.css'); $js = file_merger($arrJs,'main.js'); echo $css; echo $js; /* 函数执行成功后,会在指定的合成文件保存目录生成main.css,main.js两个文件,并会输出结果如下 <link rel="stylesheet" type="text/css" href="http://localhost/static/merger/main.css?1389454147"> <script type="text/javascript" src="http://localhost/static/merger/main.js?1389454147"></script> 测试代码的时候可以把$CFG['debug']设置为1; 当为1的时候,不会生成合成文件,同时会得到如下输出结果,方便调试: <link href="http://localhost/static/css/1.css?1389454824" rel="stylesheet" type="text/css"> <link href="http://localhost/static/css/2.css?1389454824" rel="stylesheet" type="text/css"> <script type="text/javascript" src="http://localhost/static/js/1.js?1389454824"></script> <script type="text/javascript" src="http://localhost/static/js/2.js?1389454824"></script> */
file_merger有两种压缩方式,一种是使用雅虎基于java开发的yuicompressor,第二种就是我基于PHP正则表达式编写的压缩规则。优先推荐使用yuicompressor的压缩方式,但如果你的服务器环境不支持java,也可以使用第二种方法。
下边是file_merger函数的实现代码,如果使用过程中有什么问题,可以给我留言。
<?php /* 作者:moyancheng 最后更新时间:2013-05-17 最后更新时间:2013-12-13 功能:将多个js或css,合并为一个js或css,并进行压缩 $arrPath:合并文件数组 $out:输出文件 $cache:是否缓存,默认为false,会在文件名后边加上时间戳,如main.js?1389424132 */ function file_merger($arrFile,$out,$cache=false) { global $CFG; $url = 'http://localhost/static/';//静态资源url地址,根据自己的情况修改 $static = '/static/';//静态资源在服务器上的存储路径,根据自己的情况修改 $dir = "{$static}merger/";//合成文件在服务器上的存储路径,根据自己的情况修改 $return = "{$url}merger/{$out}"; $out = "{$dir}{$out}";// $time = $_SERVER['REQUEST_TIME']; if( substr($arrFile[0],-2) == 'js' ) { $type = 'js'; } elseif( substr($arrFile[0],-3) == 'css' ) { $type = 'css'; } //当文件不存在,或者调试模式,就执行下边的程序 if( !is_file($out) || $CFG['debug']) { //调试模式,按常规加载js,css if( $CFG['debug'] ) { $out = ''; foreach($arrFile as $key => $file) { if( $type == 'js' ) { $out .= "<script type=\"text/javascript\" src=\"{$url}js/{$file}?{$time}\"></script>\n"; } elseif( $type == 'css' ) { $out .= "<link href=\"{$url}css/{$file}?{$time}\" rel=\"stylesheet\" type=\"text/css\">\n"; } } return $out; } else { //正式环境启动压缩 ob_start(); foreach($arrFile as $key => $file) { include $static."{$type}/{$file}"; } $str = ob_get_clean(); $tmp = $dir. 'tmp'; if($CFG['java']) { //java程序精简文件 file_put_contents($tmp,$str); if( $type == 'js' ) { $exec = "java -jar {$static}yuicompressor-2.4.2.jar --type js --charset utf-8 -v $tmp > $out";//压缩JS } elseif( $type == 'css' ) { $exec = "java -jar {$static}yuicompressor-2.4.2.jar --type css --charset utf-8 -v $tmp > $out";//压缩CSS } `$exec` ; } else { //php程序精简文件 $str = preg_replace( '#/\*.+?\*/#s','', $str );//过滤注释 /* */ $str = preg_replace( '#(?<!http:)(?<!\\\\)(?<!\')(?<!")//(?<!\')(?<!").*\n#','', $str );//过滤注释 // $str = preg_replace( '#[\n\r\t]+#',' ', $str );//回车 tab替换成空格 $str = preg_replace( '#\s{2,}#',' ', $str );//两个以上空格合并为一个 file_put_contents($out,$str); } } } unset($CFG); if( $cache ) { if( $type == 'js' ) return "<script type=\"text/javascript\" src=\"{$return}\"></script>\n"; elseif( $type == 'css' ) return "<link rel=\"stylesheet\" type=\"text/css\" href=\"{$return}\">\n"; } else { if( $type == 'js' ) return "<script type=\"text/javascript\" src=\"{$return}?{$time}\"></script>\n"; elseif( $type == 'css' ) return "<link rel=\"stylesheet\" type=\"text/css\" href=\"{$return}?{$time}\">\n"; } }
我来说两句: