当前位置: 首页 > news >正文

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。

http://www.jsqmd.com/news/1125847/

相关文章:

  • 基于微软Dryad分布式并行计算平台云技术的研究
  • MIX 11 细节梳理 Windows phone 7 Session
  • Codex代理配置实战:用国产大模型替代OpenAI API的完整指南
  • 绝影马:7.8起美国CPSC电子申报强制执行,未合规将遭清关扣留!
  • ParsecVDisplay:Windows虚拟显示器的终极免费解决方案
  • 从团队项目角度看 AI API 聚合平台:别等成本失控后才补日志
  • 2026深度研习八字排盘工具怎么选:看结构复盘、案例沉淀和AI边界
  • 首先在code behind中加入以下方法
  • 一撸猫就喷嚏不停?毛发过敏,真不全是毛的锅
  • HBuilderX 创建 Vue3 uniCloud 项目
  • 构建AI知识库SOP:用RAG与GitCode实现品牌信息精准引用
  • DeepSeek-V3.2 二五折半年记:低价 API 到底把哪些场景做了起来
  • 使用DryadLINQ
  • 深入解析TipDM大数据挖掘建模平台:从拖拽式可视化建模、全生命周期管理到产学研一体化应用的实战指南
  • Windows Phone 7重量级版本升级 - Mango (芒果)
  • 【SI_加重技术】快速了解高速信号传输加重技术
  • Learn Harness Engineering 课程全总结:12 讲核心要点
  • Qt 高级编程 034:深耕QWidget底层内核—彻底吃透无边框窗口设计核心原理
  • 自动化设备为什么要用减速机?以 ANDANTEX(恩坦斯特)精密传动选型为例
  • Power BI工具提示实战:构建可交互的微型子报表
  • 推荐六款小众实用宝藏APP
  • DeepLabv3+ 特征图可视化实战:从单通道提取到伪彩色映射的5步流程
  • EdgeRemover:Windows 10/11 中专业卸载Microsoft Edge的终极解决方案
  • 如何高效使用QRazyBox:终极二维码修复与恢复完全指南
  • 天学网英语听力对孩子有用吗?2026最新实测给家长靠谱答案
  • 什么是函数式编程
  • 为什么网卡停止收包?——Intel网卡RX Buffer Replenishment机制深度解析(上)
  • Bellman方程 - RL强化学习中价值估计的数学根基
  • LangChain快速入门-03Retrieval(上)
  • 为什么测试这么难写?