noF5——人人网前端自动刷新工具

noF5——人人网前端自动刷新工具

浏览次数:次 2012年09月08日 人人网FED Team 字号: 大 中 小

俗话说,磨刀不误砍柴工。

作为前端开发工程师,每天接触最多的就是HTML/CSS/JavaScript,而做的最多的事情就是:

1、修改代码

2、保存文件

3、编译合并文件

4、刷新浏览器

修改代码和保存文件等过程的优化,涉及到编辑器的选择和定制、代码的自动生成等内容,不是本文讨论的重点。

编译合并文件这个步骤,人人前端架构组给出的静态项目管理工具(OPM),已经非常好的实现了文件的自动编译合并,只需要修改原子文件,刷新浏览器,即可看到原子文件合并以后的最终效果。

因此还剩下最后一步:刷新浏览器。如何在OPM自动合并的基础上,实现改动内容的自动刷新,是目前最迫切需要解决的问题。

试想一下,如果能有修改代码“自动合并”并且同时“自动刷新浏览器”的工具,攻城师们就只需要看着显示器A修改代码,然后瞄一眼显示器B上的不同浏览器的显示效果是否正确就可以了,对于前端开发来说,这是多么惬意的事情!

人人前端自动刷新工具的要求

理想虽然很丰满,但是现实还是很骨感的。要实现自动刷新的功能,还要付出很多的努力。

结合人人前端目前开发的实际情形来看,如果需要在人人前端开发过程实现自动刷新,则自动刷新工具必须满足以下几个方面的要求:

1、能够实现原子文件修改的自动刷新,如果页面访问的ab.js是由a.js和b.js合并而成,则修改a.js也能触发页面的自动刷新。

2、能够良好的实现跨域,不论是www.renren.com、photo.renren.com,还是zhan.renren.com、apps.renren.com,都要能够实现自动刷新。

3、HTML可能不在本地,有可能在内部测试服务器上,或者直接用线上代码,这种情况是经常出现的,需要支持。

4、由于页面的脚本、样式请求数目较多,期望尽量减少页面请求的发送数量和频率。

5、需要对页面的脚本、样式请求进行过滤,只检测开发时用到的脚本或样式的改动,对于广告脚本、JSONP请求脚本、统计脚本等特殊请求则不进行检测。

6、减少自动刷新相关脚本对开发和部署过程的影响,最好能做到对产品开发脚本和样式的零污染,彻底避免将自动刷新相关的脚本带到线上。

目前已有的工具分析

针对以上的一些需求,我们分析了现有的一些比较经典的工具或脚本,并且对这些工具或脚本的实现原理与优缺点进行了分析。

我们分析的对象主要包括:脚本live.js和cssrefresh.js,工具F5的免费版。

live.js和cssrefresh.js原理与分析

通过阅读live.js和cssrefresh.js的源代码,虽然cssrefresh.js只刷新样式,但是实际上,这两段脚本的实现原理是非常类似的,大概的处理过程如下:

1、获取页面所有的script/link标签,进而得到页面的脚本和样式链接请求地址,然后把这些地址加入检测队列中。

2、检测是否需要支持html修改的刷新,如果是,则将html对应地址也加入检测队列中(这里默认html是本地文件)。

3、初始状态下,针对每一个需要检测的队列成员,利用XHR对象发送异步HEAD请求,获取并记录队列成员对应的磁盘文件的时间戳或Etag。

1
2
3
4
5
6
7
8
9
10
11

var xhr = window.XMLHttpRequest ?
new XMLHttpRequest() :
new ActiveXObject("Microsoft.XmlHttp");
xhr.open("HEAD", url, true);
xhr.onreadystatechange = function () {
xhr.getAllResponseHeaders();
for (var h in headers) {
var value = xhr.getResponseHeader(h);
info[h] = value;
}
};

4、接下来,每隔一定的时间间隔(例如1秒钟),对所有的检测队列成员再次发送异步HEAD请求,查看磁盘文件对应的时间戳或Etag,如果有变化,则执行对应文件的刷新(如果是html或js,则刷新页面;如果是css,则刷新单个样式文件)。

1
2
3
4
5
6
7
8
9
10

heartbeat: function () {
if (document.body) {
// make sure all resources are loaded on first activation
if (!loaded) {
Live.loadresources();
}
Live.checkForChanges();
}
setTimeout(Live.heartbeat, interval);
}

此方案的优点在于:

1、可以轻松的获得文件修改的情况,无须考虑跨域的问题

2、脚本可复用性强,页面只要引入脚本,即可使用自动刷新功能

但是此方案的缺点也非常明显:

1、有的资源不允许HEAD请求。

2、无法很好的支持合并前的原子文件的修改的自动刷新,例如:ab.js是由a.js和b.js合并而成,由于页面中只有ab.js的引用,没有a.js和b.js的引用,因此a.js或b.js文件的修改无法正确检测。

3、如果页面脚本或样式较多,将不停的发送head请求,给浏览器造成额外负担。试想如果页面有10个脚本和10个样式,每一秒发送20个head请求,想想就有点恐怖哇。

4、对页面的脚本没有进行区分,比如广告脚本、JSONP脚本、页面统计的脚本,都会加入到检测队列中,而这些实际上并不需要。

5、页面中需要显式加入对自动刷新脚本的引用,对于HTML不在本地的情况,并不能良好的适应。

F5免费版的原理与分析

免费版的F5只能支持HTML修改的自动刷新,JS和CSS的自动刷新要收费版才提供,个人只使用过F5的免费版,因此本文只分析免费版F5的原理,收费版的原理与免费版应该是类似的(如果不同,还请开发F5的同学批评指正)。

F5的免费版的实现原理如下:

1、F5控制台本身是一个轻量级的HTTP服务器,该服务器拥有固定的IP和端口号,比如:127.0.0.1:80(如果是80,作为HTTP默认端口,可省略)。

2、如果某一个文件需要自动刷新,则必须将其放入F5的控制台,因此可以理解为:放入F5控制台的所有文件都会加入到检测队列中。

3、从F5界面给出的地址打开HTML页面(如http://127.0.0.1/index.html),此时,F5的HTTP服务器会在此页面的顶部加入jQuery和F5的功能脚本的引用。

4、请求的页面打开以后,F5的功能脚本每隔一定的时间间隔(200毫秒),往F5 HTTP服务器上发送异步GET请求/con/changes。(删除部分表示:按照F5作者的描述进行的修正,下同)

4、F5的功能脚本每隔200毫秒建立一个长连接,长连接持续时间为20秒,也就是没有文件变更的情况下,每20秒一个请求,如果有文件变更,则更新页面内容的同时再发送一个长连接请求

5、F5控制台程序收到/con/changes请求后,检测所有放入F5控制台的文件是否有变动,如果有变动则执行对应文件的刷新(由于免费版的只支持html,所以每次都会刷新整个页面,据说收费版会刷新单个样式文件) (免费版的只支持文件改动时刷新整个页面,收费版的会支持刷新单个样式文件)

F5方案的优点包括:

1、在服务器中统一管理需要自动刷新的文件,精确而且可视化的定位了需要自动刷新的文件,所见即所得。

2、通过单个异步GET请求,检测所有需要刷新的文件的修改状态,而不是通过一大堆的HEAD请求逐个检测,提高了处理效率,避免了控制台的请求膨胀,解放了浏览器。

3、提供了图形化的操作界面,方便开发人员使用。

4、同时F5还有一个比较人性的地方:它会在自动刷新页面之前,在Cookie里帮你保存滚动条的位置,在自动刷新以后还原滚动条的位置。

F5自动刷新方案的缺点也有不少:

1、与前面的方案一样,无法很好的支持合并前的原子文件修改自动刷新

2、无法跨域,只能在F5给定的IP下本地操作

3、所有需要检测的文件都要加入F5的控制台当中,即需要明确纳入F5的自动管理

4、每200毫秒发送一次异步请求到F5的HTTP服务器,还是负担有点重!

5、F5的JS和CSS自动刷新是收费的,唉~

5、F5的CSS单个文件自动刷新是收费的,唉~

noF5的最终实现方案

由于目前现有的一些工具和脚本不能满足人人前端的开发需求,因此我们实现了一个符合人人前端开发要求的自动刷新工具,目前命名为noF5,即“不需要手动按F5刷新”,另外也稍微表达了一下对F5需要收费的抗议(吐槽,噱头而已,请大家息怒 ^_^)。

针对需要满足的几个要求,本工具给出的解决方案如下:

1、采用长连接的方式,默认每一个请求持续40秒,直到后端检测到有文件改动,如果超时则重复发送。这样可以避免多次快速的往后端发送请求。

2、将页面的脚本和样式地址进行过滤,并且在发送长连接时,将页面的脚本和样式进行过滤整理以后,通过请求参数的方式发送至后台服务器,进行处理。这样可以避免对JSONP、广告等脚本的多余检测。

3、由于首页框架的存在,首页打开不同的子页时,同一个页面(首页)上的脚本和样式可能会发生变化,因此每一次发送长连接请求之前都需要对当前页面存在的脚本和样式做一遍筛选和清理工作。

4、让工具的使用者将test.renren.com绑定到本地的开发目录,并且在开发目录下放置跨域相关的文件(例如ajaxproxy.htm)。这样就能实现轻松跨域。

5、让工具的使用者在nginx中对test.renren.com的opm/f5的请求进行配置,将该请求自动转发到后台服务器中。

6、利用OPM提供的相关功能,获取合并文件对应的原子文件列表,并在后端程序中对列表中的文件修改情况进行循环检测。将循环检测放到后端程序中进行,解放浏览器,解放生产力。

7、在OPM开发模式下,通过opm serve命令启动本地服务器,开启脚本和样式的自动合并,此时如果将自动刷新相关的脚本加入到合并以后的脚本之中,即可“浑水摸鱼”“偷梁换柱”,对发布模式下合并出的最终发布的代码不会产生任何影响,从而达到产品代码零污染的目的。

结合以上解决方案,noF5的体系结构设计如下图所示:

其中,HTTP服务器是通过OPM serve命令启动的WSGIServer,noF5与OPM共用同一个服务器,可以减少系统开销,并且降低开发人员的学习和配置成本。

noF5的自动刷新处理流程如下图所示:

使用与效果

人人前端攻城师利用如下命令开启OPM服务器,并且打开noF5的调试模式:

1

opm serve --fastcgi D:workhomeworkspace --debug --hg --f5 --f5debug

此时访问人人首页,页面显示内容如下:

在firebug控制台可以看到如下日志和请求内容:

可以看到一个正在滚动的请求,这就表示正在利用长连接,检测后台文件是否改动。

接下来我们尝试修改一个合并文件对应的原子文件。目前首页中使用了如下链接对应的CSS文件:

http://s.xnimg.cn/a43792/n/core/home-frame2-all-min.css

此文件是由20多个css 原子文件合并而成,我们修改其中的某一个原子文件v6guide.css,为body添加border:

1
2
3

body {
border: 11px solid red;
}

修改保存文件以后,页面将会自动刷新此链接对应的home-frame2-all-min.css文件,只需要把视线从开发显示器转移到浏览的显示器,就可以发现页面样式已经发生变化。如下图所示:

并且此时控制台将会多出一部分内容:

可以看到上一个长连接请求持续了22秒以后最终完成,并且返回了一个css文件的名称,另外又多出一个长连接请求来。

说明此时已经完成了一次自动刷新的操作,下一次长连接的请求已经发出,后台正在紧锣密鼓的进行下一次修改内容的检测。

总结

目前此自动刷新工具已经在人人前端开发中得到了普遍的应用,对于前端开发人员的开发效率提升非常明显。

前端攻城师们,特别是人人FED的前端攻城师们:

你还在抱怨IE老是不能正确清空缓存导致被迫每次刷新之前都要使用一次CCleaner么?

你还在觊觎网上的F5“改动文件自动刷新页面”的功能但是又对F5需要收费才能自动刷新样式和脚本咬牙切齿么?

你还在只打开一个火狐调试样式完成之后心惊胆颤的打开IE6祈祷IE下也能正常但是不幸的是IE样式错乱整得你顿时就想砸电脑么?

你还在抱怨为了调试IE的样式总是不断刷新页面导致IE越来越卡越来越慢内存越吃越多最后只能被迫无奈的杀死进程或者关闭浏览器后重新启动么?

不用抱怨了,不用觊觎了,不用羡慕嫉妒恨了,noF5终于来了!




转载请注明:http://www.soiphoto.com/gznr/gznr/29.html