一个完整html的加载执行过程

本文详细介绍了在浏览器输入地址回车后,加载与渲染HTML的过程。加载HTML文件包含排队、DNS解析等步骤;解析HTML时构建DOM树,匹配引用文件,按顺序加载渲染资源。渲染过程包括构建DOM树、呈现树,进行布局和绘制,还说明了相关概念及解析顺序的影响。

在浏览器输入地址按回车后,执行如下操作:

1、加载html文件

包括:排队-》与代理服务器连接通讯-》DNS解析(不同域名)-》建立连接-》发送请求-》等待服务器相应,即第一个字节发过来-》接受相应数据,即整个html文档内容数据-》直到接收到最后一个字节。
注:加载文件即指上述过程

具体见转载: 从输入 URL 到页面加载完成的过程

2、开始解析html

2.1 解析meta信息,构建基本DOM树。

2.2 浏览器匹配出所有引用文件,使它们都处于挂起状态。

包括script引用的外部js文件、link引用的css文件和html中直接引用的图片。

2.3 若head标签中有script标签或link标签,则开始按顺序渲染或加载js,css。

若遇到link标签,开始加载css文件。
同时顺序解析DOM元素,并构建DOM树。
若后面有js脚本,则脚本会被阻塞,直到css加载并解析完毕才会执行js脚本。
若后面有外部js脚本,则并行加载js脚本,但会等css加载并解析完毕才会执行外部脚本。加载前会先将此script标签解析到Elements中。
若碰到img标签,则加载图片资源。但不会等待下载,还是继续向下解析。解析的同时若图片下载完则会占空间。

2.4 继续解析,直到遇到html结束标签。

注:关于script和link的书写顺序,这样定义:link和style在head里,script在body最后。这是因为js一般用来操作DOM元素,而html会动态渲染样式。
若script放在body之前任何位置,要是有对DOM的操作,包括样式操作,浏览器会重新去渲染这个元素,然后才继续向下渲染。要是此时DOM不存在则会报错。
script放在body结尾处时,所有的DOM元素都已渲染完,此时js再操作DOM不会报错,且减少了DOM渲染次数。

渲染过程详解

1、构建DOM树
2、DOM树与CSS样式进行附着构造呈现树
3、布局
4、绘制

1、解析与构建DOM树:

浏览器有专门的html解析器,解析HTML并在解析的过程中构建DOM树(即在Elements中呈现)。

浏览器是自上而下解析的。

有两种DOM元素在解析的过程中会阻塞浏览器的解析。即样式(link、style)与脚本文件(script)。
在遇到这些元素时,会阻塞浏览器的解析,直到外部资源加载并解析或执行完毕后才会继续向下解析html。

样式与脚本的先后顺序会影响解析过程,具体有4个结论:
a、外部样式会阻塞后续脚本的执行,直到外部样式加载并解析完毕。
b、外部样式不会阻塞后续外部脚本的加载,但会阻塞外部脚本的执行。
即外部脚本与外部样式会并行加载,但直到外部样式加载完毕,外部脚本才开始执行。
c、如果后续外部脚本含有async属性,则外部样式不会阻塞该脚本的加载与执行。
d、动态创建的link标签不会阻塞其后动态创建的script的加载与执行,不管script标签是否含有异步属性。

以上解析顺序自上而下,遇到link style与脚本文件,样式标签会互相影响script标签,但html中引用的其他资源仍会并行加载,不会影响script脚本的执行。

加载的时候会同步构建DOM树。
然后开始解析body中的元素。

html元素解析完毕,DOM树创建完成后,会触发DOMContentLoaded事件,此时可用script来操作DOM节点。

2、构建呈现树RenderTree

构建呈现树的过程,即将CSS样式应用到DOM节点上。
DOM树 + CSS样式 —构建—》 呈现树

呈现树的含义:它的每一个节点即为与其相对应的CSS框,包括block框、inline框。也就是框组成的树。
注:呈现树节点在呈现树中的位置与它们在DOM树中的位置理论上一样,但float与绝对定位元素除外。

3、布局

呈现树构造完成后浏览器便进行布局处理,即计算每个呈现树节点的大小和位置信息。

这里可以这样理解,之前附着到DOM节点上的样式信息只是存在内存里,并没有实际使用,浏览器要根据窗口的实际大小来处理呈现树节点的实际显示大小和位置,比如对于margin为auto的处理。

布局是一个递归过程,从根呈现节点开始,递归遍历子节点,计算几何信息。

4、绘制

将呈现树绘制出来显示在屏幕上。

对于每一个呈现树节点来说,主要绘制顺序如下:
背景颜色
背景图片
边框
子呈现树节点
轮廓

备注

加载、下载、解析、执行概念
加载:下载
解析:分析代码中是否有特殊额外操作,如含require则根据特定规则决定下载该文件,如遇引用外部js文件则根据特定规则决定是否立马下载该外部js文件。
执行:运行代码。每种语言都有自己的运行时机。如CommonJS中require时,会加载文件并在加载完成后立马执行代码。

参考
http://www.cnblogs.com/dojo-lzz/p/3983335.html

<think>我们讨论的是在HTML加载时直接执行函数的方法。通常,我们希望在页面加载过程中或加载完成后立即执行一些JavaScript函数。以下是一些常见的方法: 1. 使用window.onload事件 2. 使用DOMContentLoaded事件 3. 直接在script标签中写函数调用(注意放置位置) 4. 使用defer或async属性 5. 使用jQuery的$(document).ready() 下面我将分别给出示例代码,并解释每种方法的执行时机。</think>### HTML页面加载时自动执行函数的实现方法 #### 1. 立即执行函数表达式 (IIFE) ```html <script> // 页面加载时立即执行 (function() { console.log("页面开始加载执行"); // 初始化操作 document.documentElement.classList.add("loading"); })(); </script> ``` #### 2. DOMContentLoaded 事件 ```html <script> // DOM解析完成后执行(无需等待图片等资源) document.addEventListener('DOMContentLoaded', () => { console.log("DOM加载完成"); // 初始化UI组件 initCarousel(); setupEventListeners(); }); </script> ``` #### 3. window.onload 事件 ```html <script> // 页面所有资源加载完成后执行 window.onload = function() { console.log("所有资源加载完成"); // 执行依赖完整页面的操作 preloadImages(); startAnalytics(); }; </script> ``` #### 4. 内联脚本(同步执行) ```html <body> <!-- 脚本在解析到该位置时立即执行 --> <script> console.log("同步脚本执行时间:", new Date()); document.getElementById('loader').style.display = 'block'; </script> <!-- 页面内容 --> <div id="content">...</div> </body> ``` #### 5. 异步脚本加载执行 ```html <script async> // 异步加载脚本,下载完成后立即执行 (async function init() { console.log("异步脚本执行"); const data = await fetchData(); renderContent(data); })(); </script> ``` ### 高级执行控制方法 #### 1. 带依赖的模块加载 ```html <script type="module"> // ES模块加载执行 import { initApp } from './app.js'; document.addEventListener('DOMContentLoaded', () => { initApp({ theme: 'dark', apiKey: 'XYZ123' }); }); </script> ``` #### 2. 执行顺序控制 ```html <script src="vendor.js"></script> <!-- 先加载依赖 --> <script> // 确保依赖加载执行 if (window.MyLibrary) { MyLibrary.initialize(); } else { console.error("依赖库未加载"); } </script> ``` #### 3. 性能优化版 ```html <script> // 使用requestIdleCallback在空闲时执行 function runWhenIdle() { if ('requestIdleCallback' in window) { requestIdleCallback(() => { console.log("浏览器空闲时执行"); processLowPriorityTasks(); }); } else { setTimeout(processLowPriorityTasks, 1000); } } // 页面主要内容加载执行 document.addEventListener('DOMContentLoaded', runWhenIdle); </script> ``` ### 最佳实践建议 1. **执行顺序策略**: ```javascript // 推荐的执行顺序 (function() { // 1. 立即执行初始化 setGlobalFlags(); // 2. DOM就绪后执行主逻辑 document.addEventListener('DOMContentLoaded', initMainApp); // 3. 页面完全加载执行次要任务 window.addEventListener('load', loadSecondaryResources); // 4. 空闲时执行非关键任务 window.addEventListener('load', () => { requestIdleCallback(loadNonCriticalAssets); }); })(); ``` 2. **错误处理**: ```javascript window.addEventListener('error', (event) => { console.error(`加载错误: ${event.message}`, event.error); showFallbackUI(); }); window.addEventListener('unhandledrejection', (event) => { console.error("未处理的Promise异常:", event.reason); }); ``` 3. **性能监控**: ```javascript // 记录关键时间点 performance.mark('start_execution'); document.addEventListener('DOMContentLoaded', () => { performance.mark('dom_ready'); performance.measure('DOM加载时间', 'start_execution', 'dom_ready'); }); window.addEventListener('load', () => { performance.mark('page_loaded'); performance.measure('完整加载时间', 'start_execution', 'page_loaded'); reportMetrics(); }); ``` ### 不同方法的执行时机比较 | 方法 | 执行时机 | 是否阻塞渲染 | 适用场景 | |------|----------|--------------|----------| | IIFE | 解析到脚本时立即执行 | 是 | 极早期初始化 | | 内联脚本 | 解析到位置立即执行 | 是 | 关键渲染路径优化 | | DOMContentLoaded | DOM树构建完成 | 否 | 主UI初始化 | | window.onload | 所有资源加载完成 | 否 | 完整页面操作 | | async脚本 | 下载完成后立即执行 | 否 | 独立功能模块 | | requestIdleCallback | 浏览器空闲时 | 否 | 非关键后台任务 |
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值