浏览器加载、渲染和解析过程黑箱简析


Posted in Javascript onNovember 29, 2012

用 Fiddler 监控,在 IE6 下,资源下载顺序为:
浏览器加载、渲染和解析过程黑箱简析

很明显,下载顺序从上到下,文档流中先出现的资源先下载。在 IE8, Safari, Chrome 等浏览器下也类似。

Firefox 对下载顺序做了优化
浏览器加载、渲染和解析过程黑箱简析
Firefox 会将 js, css 提前下载,而将图片等资源延迟到后面下载。

对于渲染,利用 Fiddler 将网速调慢,可以看到 css 下载后会马上渲染到页面,渲染和下载同步进行。js 的解析和运行,也类似。

对于 js 运行,以及页面加载相关事件的触发,特别做了测试。在 Firefox 下,打开测试页面:

[22:13:32.947] HTML Start[22:13:32.947] normal inline script run time[22:13:34.904] normal external script run time[22:13:35.775] [body] normal external script run time[22:13:35.789] [body end] normal external script run time[22:13:35.789] HTML End[22:13:35.791] deferred inline script run time[22:13:35.791] deferred external script run time[22:13:35.793] DOMContentLoaded[22:13:38.144] images[0] onload[22:13:38.328] images[1] onload[22:13:39.105] images[2] onload[22:13:39.105] images[3] onload[22:13:39.106] window.onload

很明显,JS 的运行严格按照文档流中的顺序进行。其中 deferred 的脚本会在最后运行(注:Firefox 3.5 开始支持 defer,而且支持得很完美)。

再来看下 IE8,结果如下:

[22:33:56.806] HTML Start[22:33:56.826] normal inline script run time[22:33:57.786] normal external script run time[22:33:57.812] deferred inline script run time[22:33:57.816] document.readyState = interactive[22:33:57.934] [body] normal external script run time[22:33:58.310] [body end] normal external script run time[22:33:58.310] HTML End[22:33:58.346] deferred external script run time[22:33:58.346] images[0].readyState = loading[22:33:58.346] images[0].readyState = complete[22:33:58.346] images[0] onload[22:33:58.361] doScroll[22:33:58.451] images[1].readyState = loading[22:33:58.479] images[1].readyState = complete[22:33:58.479] images[1] onload[22:33:58.794] images[2].readyState = loading[22:33:58.854] images[2].readyState = complete[22:33:58.854] images[2] onload[22:33:58.876] images[3].readyState = loading[22:33:58.876] images[3].readyState = complete[22:33:58.876] images[3] onload[22:33:58.887] document.readyState = complete[22:33:58.888] window.onload

可以看出,IE8 下,defer 只对 external 脚本有效,对 inline 脚本无效。另,与 DOMContentLoaded 最接近的是 doScroll. 这是 doScroll 被广泛用来模拟 DOMContentLoaded 的原因。小心:仅仅是模拟,细节上并不等价。

还可以得到一个有点意外的结果:放在 body 结束前的脚本,执行时,依旧最好放在 domready 事件中。无论在 Firefox 还是 IE 下,解析到 HTML End 时,并不代表 DOM 可以安全操作,特别是页面比较复杂时。

从上面数据中,也可以看出 YSlow 性能优化法则里,建议将样式置顶和脚本置底的根据。

有兴趣的可以进一步测试动态添加样式和脚本的情形,会稍有不同,但没有特别 surprise.

最后总结下

页面资源的下载顺序是从上到下的,文档流中先出现的资源先下载(注:存在并发,具体请参考 UA Profiler)。当某一样式下载完成时,会立刻渲染到页面(体现了层叠样式表中层叠在渲染时的含义)。当某一脚本下载完成时,也会立刻解析和运行。脚本的运行严格按照文档流中的顺序进行,deferred 的脚本会在正常脚本运行之后运行(Firefox 和 IE 下)。

特别需要留意:脚本运行时,会暂停该脚本之下所有资源的下载(因为脚本可能改变文档流,甚至跳转页面,浏览器的暂停策略是合理的)。要小心内联脚本,经常会阻塞后续下载。

好了,废话不多说。以上结果,建议各位亲自测试,反复测试,疯狂测试,一直到眼花缭乱稀里糊涂恍然大悟继续糊涂为止……

Javascript 相关文章推荐
js读写(删除)Cookie实例详解
Apr 17 Javascript
jQuery实现简单网页遮罩层/弹出层效果兼容IE6、IE7
Jun 16 Javascript
快速学习AngularJs HTTP响应拦截器
Dec 31 Javascript
BootStrap的table表头固定tbody滚动的实例代码
Aug 24 Javascript
Javascript 实现放大镜效果实例详解
Dec 03 Javascript
jquery实现下拉框多选方法介绍
Jan 03 Javascript
使用JavaScript实现alert的实例代码
Jul 06 Javascript
如何编写一个完整的Angular4 FormText 组件
Nov 18 Javascript
解决easyui日期时间框ie的兼容的问题
Mar 01 Javascript
JSON生成Form表单的方法示例
Nov 21 Javascript
如何根据业务封装自己的功能组件
Apr 19 Javascript
js 计数排序的实现示例(升级版)
Jan 12 Javascript
javascript控制swfObject应用介绍
Nov 29 #Javascript
javascript 保存文件到本地实现方法
Nov 29 #Javascript
jquery连缀语法如何实现
Nov 29 #Javascript
javascript 使td内容不换行不撑开
Nov 29 #Javascript
json原理分析及实例介绍
Nov 29 #Javascript
javascript全局变量封装模块实现代码
Nov 28 #Javascript
Javascript Request获取请求参数如何实现
Nov 28 #Javascript
You might like
PHP的PDO错误与错误处理
2019/01/27 PHP
javascript IFrame 强制刷新代码
2009/07/23 Javascript
javascript 子窗体父窗体相互传值方法
2010/05/31 Javascript
JavaScript高级程序设计 阅读笔记(七) ECMAScript中的语句
2012/02/27 Javascript
PHP中使用微秒计算脚本执行时间例子
2014/11/19 Javascript
js实现横向伸展开的二级导航菜单代码
2015/08/28 Javascript
javascript图片滑动效果实现
2021/01/28 Javascript
简单理解js的冒泡排序
2016/12/19 Javascript
jQuery简单获取DIV和A标签元素位置的方法
2017/02/07 Javascript
jQuery插件HighCharts绘制简单2D柱状图效果示例【附demo源码】
2017/03/21 jQuery
基于bootstrap实现bootstrap中文网巨幕效果
2017/05/02 Javascript
React Native之TextInput组件解析示例
2017/08/22 Javascript
浅谈js基础数据类型和引用类型,深浅拷贝问题,以及内存分配问题
2017/09/02 Javascript
JavaScript面向对象继承原理与实现方法分析
2018/08/09 Javascript
Vue自定义toast组件的实例代码
2018/08/15 Javascript
Vue-CLI3.x 设置反向代理的方法
2018/12/06 Javascript
[00:12]2018DOTA2亚洲邀请赛SOLO赛 MidOne是否中单第一人?
2018/04/05 DOTA
python实现登录密码重置简易操作代码
2019/08/14 Python
Pytorch之Variable的用法
2019/12/31 Python
python模拟实现分发扑克牌
2020/04/22 Python
浅谈python 调用open()打开文件时路径出错的原因
2020/06/05 Python
Scrapy 配置动态代理IP的实现
2020/09/28 Python
python爬取音频下载的示例代码
2020/10/19 Python
python爬虫如何解决图片验证码
2021/02/14 Python
html5+css3之CSS中的布局与Header的实现
2014/11/21 HTML / CSS
HTML5边玩边学(3)像素和颜色
2010/09/21 HTML / CSS
一道Delphi上机题
2012/06/04 面试题
测控技术与仪器个人求职信范文
2013/12/30 职场文书
高二英语教学反思
2014/01/19 职场文书
西式结婚主持词
2014/03/14 职场文书
联谊活动总结
2014/08/28 职场文书
教师个人工作总结范文2014
2014/11/10 职场文书
解决pycharm安装scrapy DLL load failed:找不到指定的程序的问题
2021/06/08 Python
深入理解以DEBUG方式线程的底层运行原理
2021/06/21 Java/Android
Oracle安装TNS_ADMIN环境变量设置参考
2021/11/01 Oracle
Nginx设置HTTPS的方法步骤 443证书配置方法
2022/03/21 Servers