建站教程

建站教程

Products

当前位置:首页 > 建站教程 >

6张图让你搞懂浏览器渲染网页过程(js HTML DOM EventListener功能与用法)

GG网络技术分享 2025-03-18 16:14 0


6张图让你搞懂浏览器渲染网页过程

我的想法:如果我要构建快速可靠的网站,需要真正了解浏览器渲染网页的每个步骤机制,这样就可以在开发过程中对每个步骤进行优化。这篇文章是我在较高水平上对端到端过程的学习总结。

好了,废话不多说,我们开始吧。这个过程可以分为以下几个主要阶段:

  1. 开始解析HTML
  2. 获取外部资源
  3. 解析 CSS 并构建CSSOM
  4. 执行 JavaScript
  5. 合并 DOM 和 CSSOM 以构造渲染树
  6. 计算布局和绘制

1.开始解析HTML

当浏览器通过网络接收页面的HTML数据时,它会立即设置解析器将HTML转换为文档对象模型(DOM)

解析过程的第一步是将HTML分解并表示为开始标记结束标记及内容标记,然后它可以构造DOM。

2. 获取外部资源

当解析器遇到外部资源(如CSS或JavaScript文件)时,解析器将提取这些文件。解析器在加载CSS文件时继续运行,此时会阻止页面渲染,直到资源加载解析完(稍后会详细介绍)。

JavaScript 文件略有不同-默认情况下,解析器会在加载 JS 文件然后进行解析同时会阻止对HTML的解析。可以将两个属性添加到脚本标签中以减轻这种情况:defer 和async。两者都允许解析器在后台加载JavaScript 文件的同时继续运行,但是它们的执行方式不同。关于这一点后面还会再讲一点,但总的来说:

defer表示文件的执行将被延迟,直到文档的解析完成为止。如果多个文件具有defer属性,则将按照页面放置的顺序依次执行。

<scripttype="text/javascript"src="script.js"defer>

async 意味着文件将在加载后立即执行,这可能是在解析过程中或在解析过程之后执行的,因此不能保证异步脚本的执行顺序。

<scripttype="text/javascript"src="script.js"async>

预加载资源

<link> 元素的 rel 属性的属性值preload能够让你在你的HTML页面中 <head>元素内部书写一些声明式的资源获取请求,可以指明哪些资源是在页面加载完成后即刻需要的。

对于这种即刻需要的资源,你可能希望在页面加载的生命周期的早期阶段就开始获取,在浏览器的主渲染机制介入前就进行预加载。这一机制使得资源可以更早的得到加载并可用,且更不易阻塞页面的初步渲染,进而提升性能。

<linkhref="style.css"rel="preload"as="style"/>

3.解析CSS并构建CSSOM

你可能很早就知道DOM,但对**CSSOM(CSS对象模型)**可能听得少,反正我也没听过几次。

与HTML文件和DOM相似,加载CSS文件时,必须将它们解析并转换为树-这次是CSSOM。它描述了页面上的所有CSS选择器,它们的层次结构和属性。

CSSOM 与 DOM的不同之处在于它不能以增量方式构建,因为CSS规则由于特定性而可以在各个不同的点相互覆盖。这就是CSS 阻塞渲染的原因,因为在解析所有CSS并构建CSSOM之前,浏览器无法知道每个元素在屏幕上的位置。

4.执行JavaScript

不同的浏览器有不同的 JS 引擎来执行此任务。从计算机资源的角度来看,解析 JS 可能是一个昂贵的过程,比其他类型的资源更昂贵,因此优化它对于获得良好的性能是如此重要。

载入事件

加载的JS和DOM被完全解析并准备就绪后就会 emit document.DOMContentLoaded事件。对于需要访问DOM的任何脚本,例如以某种方式进行操作或侦听用户交互事件,优良作法是在执行脚本之前先等待此事件。

document.addEventListener('DOMContentLoaded',(event)=>{

//这里面可以安全地访问DOM了

});

在所有其他内容(例如异步JavaScript,图像等)完成加载后,将触发window.load事件。

window.addEventListener('load',(event)=>{

//页面现已完全加载

});

5.合并DOM和CSSOM 构建渲染树

渲染树DOMCSSOM的组合,表示将要渲染到页面上的所有内容。这并不一定意味着渲染树中的所有节点都将在视觉上呈现,例如,将包含opacity: 0或visibility: hidden的样式的节点,并仍然可以被屏幕阅读器等读取,而display: none不包括任何内容。此外,诸如<head>之类的不包含任何视觉信息的标签将始终被忽略。

与 JS 引擎一样,不同的浏览器具有不同的渲染引擎。

6. 计算布局和绘制

现在我们有了完整的渲染树,浏览器知道了要渲染什么,但是不知道在哪里渲染。因此,必须计算页面的布局(即每个节点的位置和大小)。渲染引擎从顶部开始一直向下遍历渲染树,计算应显示每个节点的坐标。

完成之后,最后一步是获取布局信息并将像素绘制到屏幕上。


作者:James Starkie 译者:前端小智 来源:dev

原文:https://dev.to/jstarmx/how-the-browser-renders-a-web-page-1ah

js HTML DOM EventListener功能与用法

本文实例讲述了js HTML DOM EventListener功能与用法。分享给大家供大家参考,具体如下:

DOM EventListener

用于向指定元素添加事件句柄。

在用户点击按钮时触发监听事件:

document.getElementById(\'myBtn\').addEventListener(\'click\', displayDate);

addEventListener() 方法添加的事件句柄不会覆盖已存在的事件句柄。

可以向一个元素添加多个事件句柄。

<script>

var x = document.getElementById(\"myBtn\");

x.addEventListener(\"mouseover\", myFunction);

x.addEventListener(\"click\", mySecondFunction);

x.addEventListener(\"mouseout\", myThirdFunction);

function myFunction() {

document.getElementById(\"demo\").innerHTML += \"Moused over!<br>\"

}

function mySecondFunction() {

document.getElementById(\"demo\").innerHTML += \"Clicked!<br>\"

}

function myThirdFunction() {

document.getElementById(\"demo\").innerHTML += \"Moused out!<br>\"

}

</script>

可以向同个元素添加多个同类型的事件句柄,如:两个 \"click\" 事件。

<script>

var x = document.getElementById(\"myBtn\");

x.addEventListener(\"click\", myFunction);

x.addEventListener(\"click\", someOtherFunction);

function myFunction() {

alert (\"Hello World!\")

}

function someOtherFunction() {

alert (\"函数已执行!\")

}

</script>

可以向任何 DOM 对象添加事件监听,不仅仅是 HTML 元素。如: window 对象。

addEventListener() 方法允许你在 HTML DOM 对象添加事件监听, HTML DOM 对象如: HTML 元素, HTML 文档, window 对象。或者其他支出的事件对象如: xmlHttpRequest 对象

<script>

window.addEventListener(\"resize\", function(){

document.getElementById(\"demo\").innerHTML = Math.random();

});

</script>

addEventListener() 方法可以更简单的控制事件(冒泡与捕获)。

当使用 addEventListener() 方法时, JavaScript 从 HTML 标记中分离开来,可读性更强, 在没有控制HTML标记时也可以添加事件监听。

可以使用 removeEventListener() 方法来移除事件的监听。

语法

element.addEventListener(event, function, useCapture);

第一个参数是事件的类型 (如 \"click\" 或 \"mousedown\").

第二个参数是事件触发后调用的函数。

第三个参数是个布尔值用于描述事件是冒泡还是捕获。该参数是可选的。

注意:不要使用 \"on\" 前缀。 例如,使用 \"click\" ,而不是使用 \"onclick\"。

事件冒泡或事件捕获?

事件传递有两种方式:冒泡与捕获。

事件传递定义了元素事件触发的顺序。 如果你将 <p> 元素插入到 <div> 元素中,用户点击 <p> 元素, 哪个元素的 \"click\" 事件先被触发呢?

在 冒泡 中,内部元素的事件会先被触发,然后再触发外部元素,即: <p> 元素的点击事件先触发,然后会触发 <div> 元素的点击事件。

在 捕获 中,外部元素的事件会先被触发,然后才会触发内部元素的事件,即: <div> 元素的点击事件先触发 ,然后再触发 <p> 元素的点击事件。

addEventListener()方法可以指定 \"useCapture\" 参数来设置传递类型:

addEventListener(event, function, useCapture);

默认值为 false, 即冒泡传递,当值为 true 时, 事件使用捕获传递。

<script>

document.getElementById(\"myP\").addEventListener(\"click\", function() {

alert(\"你点击了 P 元素!\");

}, false);

document.getElementById(\"myDiv\").addEventListener(\"click\", function() {

alert(\" 你点击了 DIV 元素 !\");

}, false);

document.getElementById(\"myP2\").addEventListener(\"click\", function() {

alert(\"你点击了 P2 元素!\");

}, true);

document.getElementById(\"myDiv2\").addEventListener(\"click\", function() {

alert(\"你点击了 DIV2 元素 !\");

}, true);

</script>

removeEventListener() 方法

removeEventListener()方法移除由addEventListener()方法添加的事件句柄:

<script>

document.getElementById(\"myDIV\").addEventListener(\"mousemove\", myFunction);

function myFunction() {

document.getElementById(\"demo\").innerHTML = Math.random();

}

function removeHandler() {

document.getElementById(\"myDIV\").removeEventListener(\"mousemove\", myFunction);

}

</script>

浏览器支持

表格中的数字表示支持该方法的第一个浏览器的版本号。

图片1

注意: IE 8 及更早 IE 版本,Opera 7.0及其更早版本不支持addEventListener()和removeEventListener()方法。但是,对于这类浏览器版本可以使用detachEvent()方法来移除事件句柄:

element.attachEvent(event, function);

element.detachEvent(event, function);

例:该实例演示了所有浏览器兼容的解决方法

<script>

var x = document.getElementById(\"myBtn\");

if (x.addEventListener) {

x.addEventListener(\"click\", myFunction);

} else if (x.attachEvent) {

x.attachEvent(\"onclick\", myFunction);

}

function myFunction() {

alert(\"Hello World!\");

}

</script>

js HTML DOM EventListener功能与用法 (https://www.wpmee.com/) javascript教程 第1张

标签:

提交需求或反馈

Demand feedback