关于Gmail登录进度条不为人知的细节

进度条是真实反映加载以及下载进度的
服务器君一共花费了792.934 ms进行了5次数据库查询,努力地为您提供了这个页面。
试试阅读模式?希望听取您的建议

Gmail 登录时,会显示一个progress bar, 显示加载的进度。最先以为是模拟的效果,但是仔细观察发现,进度条是真实反映加载以及下载进度的,并不依赖网络状况。所以非常好奇,因为在javascript中缺少检测文档下载进度的ApI(js的安全机制也禁止这样做),且只提供了加载开始,加载中,加载完成(或加载错误)等状态。那么,gmail 是如何实现实时监控加载百分比的呢?

用firebug 监控 gmail登陆时的文件下载,可以找到一个get请求,该请求返回html文本,文件大小为300多k,在其中找到这样一个函数:

function _B_prog(pct){
    top["pr"] = pct;
    if (_B_thumbStyle_ === undefined) {
        var thumb = top.document.getElementById("lpt");
        _B_thumbStyle_ = thumb ? thumb.style : null
    }
    if (_B_thumbStyle_) {
        _B_thumbStyle_.width = Math.round(pct * 0.99) + "%";
        if (pct == 100) 
            _B_thumbStyle_ = null
    }
}

该函数在html body 后定义。定义可知,进度条由该函数动态实现。

<script>
var JS_START_TIME=(new Date).getTime(),GLOBALS=top.GLOBALS;if("o_6IqNZ5hNQ.zh_CN."!=GLOBALS[4])top.location.replace(top.location.href.split("#")[0]);function _B_log(imp,opt_val){var p="imp="+imp;if(arguments.length>1)p+="&val="+opt_val;_B_logImg_("jsle",p)}var loadTimes=[GLOBALS[0],GLOBALS[1],JS_START_TIME];function _B_record(){loadTimes.push((new Date).getTime())}var _B_thumbStyle_;
function _B_prog(pct){top["pr"]=pct;if(_B_thumbStyle_===undefined){var thumb=top.document.getElementById("lpt");_B_thumbStyle_=thumb?thumb.style:null}if(_B_thumbStyle_){_B_thumbStyle_.width=Math.round(pct*0.99)+"%";if(pct==100)_B_thumbStyle_=null}}function _B_err(e){var state=loadTimes.join("-");_B_logImg_("jserr","jsstate="+encodeURIComponent(state)+"&jsmsg="+encodeURIComponent(e));_B_handleError(e)}function _B_handleError(e){throw e;}
function _B_logImg_(v,p){(new Image).src="?ui=2&view="+v+"&"+p+"&ik="+GLOBALS[9]+"&random="+(new Date).getTime()}window.onerror=function(message,url,line){_B_err(message)};
_B_prog(1);
</script>
<script>
 ....
function Ala(b){var a=[];if(b)for(;b.isValidRow();)a.push(b.field(0)),b.next();return a}function Bla(b){return b&&b.isValidRow()?b.field(0):l}function Cla(b){if(b&&b.isValidRow()){for(var a={},c=b.fieldCount(),d=0;d<c;d++)a[b.fieldName(d)]=b.field(d);return a}else return l}function Dla(b){var a=[];if(b&&b.isValidRow())for(var c=b.fieldCount(),d=0;d<c;d++)a[d]=b.field(d);return a}
function Ela(b,a,c,d){if(c.length==0||d>=c.length)return b.execute(a);else{if(ka(c[d]))return b.execute(a,c[d]);c=Array.prototype.slice.call(c,d);return b.execute(a,c)}}function Fla(b,a,c,d,e){b=Ela(b,a,d,e);try{return c(b)}finally{b&&b.close()}}function Gla(b,a){var c,d;c=a?"ROLLBACK":"COMMIT";d=a?"beforerollback":"beforecommit";var e=b.dispatchEvent(new yla(d));if(e)b.ia.execute(c),b.ka=0,d=a?"rollback":"commit",b.dispatchEvent(new yla(d));return e}
function ll(b){a:{var a=b.nb;if(b.Ma)if(b.ka==0){b.Ba=!1;b.dispatchEvent(new yla("beforebegin"));b.ia.execute("BEGIN "+a);b.eb=Hla[a];b.ka=1;try{b.dispatchEvent(new yla("begin"))}catch(c){b.ia.execute("ROLLBACK"),b.ka=0,h(c)}b=!0;break a}else b.Ba?h(Error("=106")):Hla[a]>b.eb?h(Error("=107")):b.ka++;b=!1}return b}function ml(b){if(b.Ma)if(b.ka<=0&&h(Error("=108")),b.ka==1){var a=Gla(b,b.Ba);return!b.Ba&&a}else b.ka--;return!1}function Ila(){}function Jla(b,a){this.aa=b;this.ea=a}
function Kla(b){ri(this);this.Ta=b}var Lla=GLOBALS[0],Mla=GLOBALS[2],ol=GLOBALS[3],hf=GLOBALS[4],Nla=GLOBALS[5],pl=GLOBALS[6],
ql=GLOBALS[7],Ola=GLOBALS[8],rl=GLOBALS[9],sl=GLOBALS[10],Pla=GLOBALS[11],Qla=GLOBALS[12],
Rla=GLOBALS[14],tl=GLOBALS[15],ul=GLOBALS[16],Sla=GLOBALS[17],Tla=GLOBALS[18],vl=GLOBALS[19],
Ula=GLOBALS[20],mja=GLOBALS[21],Vla=GLOBALS[22],Wla=GLOBALS[24],Xla=GLOBALS[25],Yla=GLOBALS[26],
Zla=GLOBALS[27],ama=GLOBALS[28],bma=GLOBALS[29],cma=GLOBALS[30];
_B_prog(13)}catch(e){_B_err(e)}
</script>

一直到

<script>
 ...
hL.prototype.eR=function $cvb(a,c){var d=this.ha,e=[];e[0]=w().toString(16);e[2]="0";e[18]=[a];e[24]=c;e=new Dr("^act",e);this.insertNode(mBa(d,e))};V(TLb,Er);
TLb.prototype.aa=function $dvb(a,c){var d=this.Kn.Ua.ic();if(Zr(d)&&a=="iu"){vr(this.Kn.qj());d=this.Kn.Ua;Jh(d);gra(d);d=this.Kn;wr(d.Fe);d.Ua.Sc.ea();try{for(var e=1,f;f=c[e];e++){var g=new Dr("^act",f),i=mBa(d.Ua,g);d.Fe.Jb((new LC(g.Yr()[0])).dw());var k=d.Fe,m=i.get().Yr()[0][17];if(m)for(var q=0,u=j;u=m[q];q++)k.cO(u[8])&&(fb(m,q),q--);d.Fe.insertNode(i)}d.Fe.Ba();d.aa=!0}finally{if(d.Ua.Sc.aa(),f=d.Fe,f.Se==d)f.Se=l}return!0}return!1};
TLb.prototype.ea=function $evb(a){var c=this.Kn.Ua.ic();Zr(c)&&a==0&&this.Kn.qj().dispatchEvent("Oe")};V(ULb,PAa);ULb.prototype.aa=function $fvb(){return Zr(this.Yi.ic())?new hL(this.Yi):l};V(VLb,HCa);VLb.prototype.ea=function $gvb(a,c){var d=a.getItem();c.yO=d.Sh("^act")};VLb.prototype.aa=function $hvb(a){if(a.yO){var c=new S;a.yO?Uj({Kc:"GV",title:"Buzz"},c):c.append(" ");return c.toString()}};O(N.Ja(),"t");R(N.Ja(),"t");
_B_prog(100)}catch(e){_B_err(e)}
</script>

结果很明显,进度条就是这样每加载一段js,就调用进度函数来显示进度。

但是,等等,通常加载html时,并不是一段接着一段下载并加载,而是,等整个文件下载完成后再加载执行,这样就没有实时监控下载进度的效果了。关键就是在这里,gmail并没有使用静态资源供客户端下载,而是通过类似servlet技术返回html。

这里用到了一点服务器推的技术,就是在每个</script>标签结束处调用PrintWriter.flush(), 在该方法之后,服务器端输出流会马上推送至客服端,但并没有关闭输出流,下次还可以再次调用flush(), 这样就可实现一段接一段将资源推送至客户端,实现进度监控了,而不是像目前webQQ一样模拟从0% ,然后等待,然后突然升到100%完成。

本文地址:http://www.nowamagic.net/librarys/veda/detail/1484,欢迎访问原出处。

不打个分吗?

转载随意,但请带上本文地址:

http://www.nowamagic.net/librarys/veda/detail/1484

如果你认为这篇文章值得更多人阅读,欢迎使用下面的分享功能。
小提示:您可以按快捷键 Ctrl + D,或点此 加入收藏

大家都在看

阅读一百本计算机著作吧,少年

很多人觉得自己技术进步很慢,学习效率低,我觉得一个重要原因是看的书少了。多少是多呢?起码得看3、4、5、6米吧。给个具体的数量,那就100本书吧。很多人知识结构不好而且不系统,因为在特定领域有一个足够量的知识量+足够良好的知识结构,系统化以后就足以应对大量未曾遇到过的问题。

奉劝自学者:构建特定领域的知识结构体系的路径中再也没有比学习该专业的专业课程更好的了。如果我的知识结构体系足以囊括面试官的大部分甚至吞并他的知识结构体系的话,读到他言语中的一个词我们就已经知道他要表达什么,我们可以让他坐“上位”毕竟他是面试官,但是在知识结构体系以及心理上我们就居高临下。

所以,阅读一百本计算机著作吧,少年!

《高性能网站建设指南》 桑德斯 (Steve Sounders) (作者), 刘彦博 (译者)

《高性能网站建设指南》结合Web2.0以来Web开发领域的最新形势和特点,介绍了网站性能问题的现状、产生的原因,以及改善或解决性能问题的原则、技术技巧和最佳实践。重点关注网页的行为特征,阐释优化Ajax、CSS、JavaScript、Flash和图片处理等要素的技术,全面涵盖浏览器端性能问题的方方面面。在《高性能网站建设指南》中,作者给出了14条具体的优化原则,每一条原则都配以范例佐证,并提供了在线支持。全书内容丰富,主要包括减少HTTP请求、ExpiresHeader技术、Gzip组件、CSS和JavaScript最佳实践、关闭ETags的技巧、Ajax缓存技术和最小化技术等。

更多计算机宝库...