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

用 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 下)。

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

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

(0)

相关推荐

  • 详解浏览器渲染页面过程

    详解浏览器渲染页面过程 1.解析HTML文件,创建DOM树 自上而下,遇到任何样式(link.style)与脚本(script)都会阻塞(外部样式不阻塞后续外部脚本的加载). 2.解析CSS 优先级:浏览器默认设置<用户设置<外部样式<内联样式<HTML中的style样式: 特定级:id数*100+类或伪类数*10+tag名称*1 3.将CSS与DOM合并,构建渲染树(renderingtree) DOM树与HTML一一对应,渲染树会忽略诸如head.display:none的元素

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

    用 Fiddler 监控,在 IE6 下,资源下载顺序为: 很明显,下载顺序从上到下,文档流中先出现的资源先下载.在 IE8, Safari, Chrome 等浏览器下也类似. Firefox 对下载顺序做了优化:Firefox 会将 js, css 提前下载,而将图片等资源延迟到后面下载. 对于渲染,利用 Fiddler 将网速调慢,可以看到 css 下载后会马上渲染到页面,渲染和下载同步进行.js 的解析和运行,也类似. 对于 js 运行,以及页面加载相关事件的触发,特别做了测试.在 Fir

  • 网页资源阻塞浏览器加载的原理示例解析

    目录 正文 测试前环境准备 图片会造成阻塞吗? CSS 加载阻塞 CSS 会阻塞后面 JS 的执行吗? JS 加载阻塞 defer 和 async 动态脚本会造成阻塞吗? DOMContentLoaded 和 onload DOMContentLoaded 遇到脚本 DOMContentLoaded 遇到样式 正文 一个页面允许加载的外部资源有很多,常见的有脚本.样式.字体.图片和视频等,对于这些外部资源究竟是如何影响整个页面的加载和渲染的呢?今天来一探究竟. 如何用 Chrome 定制网络加载

  • Android从xml加载到View对象过程解析

    我们从Activity的setContentView()入手,开始源码解析, //Activity.setContentView public void setContentView(int layoutResID) { getWindow().setContentView(layoutResID); initActionBar(); } //PhoneWindow.setContentView public void setContentView(int layoutResID) { if (

  • Java加载property文件配置过程解析

    这篇文章主要介绍了java加载property文件配置过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1 properties简介: properties是一种文本文件,内容格式为: key = value #单行注释 适合作为简单配置文件使用,通常作为参数配置.国际化资源文件使用. 对于复杂的配置,就需要使用XML.YML.JSON等了 2 java加载Properties: java加载properties主要通过2个util包下的

  • 使用Browserify来实现CommonJS的浏览器加载方法

    Nodejs的模块是基于CommonJS规范实现的,可不可以应用在浏览器环境中呢? var math = require('math'); math.add(2, 3); 第二行math.add(2, 3),在第一行require('math')之后运行,因此必须等math.js加载完成.也就是说,如果加载时间很长,整个应用就会停在那里等.这对服务器端不是一个问题,因为所有的模块都存放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间.但是,对于浏览器,这却是一个大问题,因为模块都放在服务

  • 概述java虚拟机中类的加载器及类加载过程

    1. 类加载子系统 1.1 概述 类加载子系统负责从文件系统或者网络中加载Class文件,Class文件在文件开头有特定的文件标识 ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine 决定 加载的类信息存放于一块成为 :方法区的内存空间,除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射) 字节码中的常量池加载到 方法区 -----> 运行时常量池信息 1

  • javascript加载xml 并解析各节点的值(实现方法)

    实例如下: var xmlDoc = null; function LoadXml(xmlPath) { try { if (window.ActiveXObject) { xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); } } catch (e) { try { xmlDoc = document.implementation.createDocument("", "", null); } cat

  • 基于Pycharm加载多个项目过程图解

    这篇文章主要介绍了基于Pycharm加载多个项目过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 今天在使用Pycharm工具练习Python时遇到一个疑问:在已存有项目A工程的前提下如何新建另一个项目B,且两者并存? 基本操作步骤: 在File下拉项中选择"New Project"弹出新界面点击"Pure Python"后创建即可,这是会弹出如图所示的提示框: 选择"Open in new win

  • JVM加载一个类的过程

    类的加载过程 Java源代码被编译成class字节码,JVM把描述类数据的字节码.Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型,这就是虚拟机的类加载机制. 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的生命周期包括了:加载(Loading).验证(Verification).准备(Preparation).解析(Resolution).初始化(Initialization).使用(Using).卸载(Unloading)七个阶段,

  • Spring多种加载Bean方式解析

    1 定义bean的方式 常见的定义Bean的方式有: 通过xml的方式,例如: <bean id="dictionaryRelMap" class="java.util.HashMap"/> 通过注解的方式,在Class上使用@Component等注解,例如 @Component public class xxxServicer{ .... } 通过在@Configuration类下的@Bean的方式,例如 @Configuration public c

随机推荐