news 2026/7/5 3:53:04

gmail loading progress bar 实现原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
gmail loading progress bar 实现原理

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>标签,标签中是压缩的js,你可以在每一段<script>定义最末找到调用_B_prog(pct)的语句,并且参数是从1

一直到100,如下所示:

<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("&nbsp;");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。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/5 3:52:59

对比同行:全链通批发进销存软件优缺点盘点

全链通批发进销存软件优缺点盘点&#xff1a;基于公开信息的客观评估与选型建议 在数字化管理日益普及的今天&#xff0c;许多中小型批发商户都在寻找适合的进销存工具。关于“全链通批发进销存软件实际使用体验怎么样”&#xff0c;由于缺乏大量独立的第三方深度测评数据&…

作者头像 李华
网站建设 2026/7/5 3:50:55

2026年静音桌面风扇:声音干净才是值得关注的静音标准

2026年静音桌面风扇&#xff1a;声音干净才是值得关注的静音标准2026年&#xff0c;静音已成为衡量桌面风扇品质的重要指标之一。但不少用户往往只看分贝数字&#xff0c;而声音是否“干净”同样值得关注。一台声音干净的风扇&#xff0c;即使分贝略高也不易让人烦躁&#xff1…

作者头像 李华
网站建设 2026/7/5 3:49:04

泛程序运营的7个核心要点,落实即可稳步提升收录

以下7个中心要害完全贴合新手落地&#xff0c;实施后就能稳步跋涉录入&#xff1a;‌内容降重打底‌用RAP泛程序的变量替换功用&#xff0c;自动调整页面语序、替换场景化要害词&#xff0c;把全部生成页面的内容重复度严厉控制在30%以内&#xff0c;从根源上避免被判定为低质内…

作者头像 李华
网站建设 2026/7/5 3:47:57

为什么要让我们的“领域模型”裸奔?(上)

我爸是个乡村小学教师&#xff0c;对我所从事的软件行业一无所知&#xff0c;但是他对我的工作稳定性表示怀疑&#xff1a;“你这做软件的&#xff0c;要是有一天软件做完了&#xff0c;你岂不是要失业了&#xff1f;”也许他想起了他作为老师的情况&#xff0c;教完一批学生&a…

作者头像 李华
网站建设 2026/7/5 3:46:35

Selenium IDE入门指南:从录制回放到Python脚本的自动化测试实践

1. 项目概述&#xff1a;为什么你需要掌握Selenium IDE&#xff1f; 如果你正在看这篇文章&#xff0c;大概率是遇到了需要重复操作网页的烦心事儿。可能是每天要登录后台下载报表&#xff0c;或者需要批量处理一堆表单数据&#xff0c;又或者想验证某个网页功能是否正常。手动…

作者头像 李华