type
status
date
slug
summary
tags
category
icon
password
HTML语义化
HTML 语义化 是指通过使用有意义的 HTML 标签来描述页面的结构和内容,从而让代码更具可读性、可维护性,并提升网页的可访问性和搜索引擎优化(SEO)。
比如:
- 使用
<header>
而不是<div>
明确表示这是网页的头部区域。
- 使用
<article>
标签表示一篇独立的内容块。
好处:
- 对机器友好,带有语义的文字表现力丰富,更适合搜索引擎的爬虫爬取有效信息,有利于SEO。除此之外,语义类还支持读屏软件,根据文章可以自动生成目录;
- 对开发者友好,使用语义类标签增强了可读性,结构更加清晰,开发者能清晰的看出网页的结构,便于团队的开发与维护。
innerText、textContent、innerHTML
- innerText
- 通过
innerText
获取的文本会自动去掉 HTML 标签,并且会根据 CSS 样式调整,例如,隐藏的元素内容(如display: none
)不会被返回。 - 当使用
innerText
设置内容时,会自动编码内容,任何 HTML 标签会被当作普通文本处理,不能插入<script>
或其他标签,避免了 XSS 攻击(跨站脚本攻击)。
- textContent
textContent
获取的是元素内所有文本内容,包括隐藏元素的文本内容。如果一个元素是通过 CSS 隐藏的(例如display: none
),它的文本内容仍然会被返回。textContent
通常比innerText
快,因为它没有考虑 CSS 样式,它只会返回或设置纯文本。
- innerHTML
- 通过
innerHTML
获取的内容是元素内部的HTML 代码,包括标签、文本和子元素。 - 由于
innerHTML
会直接插入 HTML 标签,它存在一定的安全风险。例如,如果你直接插入用户输入的内容,可能会导致 XSS(跨站脚本攻击)漏洞。
CSS动画
transform
矩阵变换来实现的
transform: translate:
- translate(10px):水平方向右移,百分比也可以
- translate(10px, 20px):水平右和垂直下移动,百分比也可以
tranform: rotate:
- rotate(30deg):整数顺时针,负数逆时针
transform-origin:
- top left:左上角为原点进行旋转
transform: scale:
- 缩放
transition
为动画添加过渡效果:

背景色、宽高、阴影都可以用transform
缓动函数:


阶跃缓动函数:

用grid实现响应式布局
在grid布局中,fr用于分配可用空间,1fr表示一等份的可用空间,可以用来创建自适应网格布局
- 这样表示将网格平均分成4列
- 也可以直接写
grid-template-columns: repeat(4, 1fr)
响应式:
- 表示每个网格列最小260px,最大1fr
- auto-fill:表示自动填充尽可能多的列,每列至少260px,每列都占1fr
子元素的布局,比如说实现第一个子元素占两行两列,其他的平均分配:
- grid-row:start/end:表示从第start行开始到第end行结束,不包括end
- grid-column:操作列,也一样
浏览器多进程/JS单线程
浏览器多进程和渲染进程多线程
- 浏览器是多进程的
- 浏览器之所以能够运行,是因为系统给它的进程分配了资源(cpu、内存)
- 简单点理解,每打开一个Tab页,就相当于创建了一个独立的浏览器进程。
浏览器的进程:
在浏览器中打开一个网页相当于新起了一个进程,进程内有自己的多线程。但有时候浏览器会将多个进程合并,例如打开多个空白标签页,就会被合并成同一个进程。
- Browser进程(控制进程):浏览器的主进程,只有一个
- 负责浏览器界面的显示,与用户交互。如前进、后退等
- 负责各个页面的管理,创建和销毁其他进程
- 将Renderer进程得到的内存中的Bitmap绘制到用户界面上
- 网络资源的管理和下载等
- 浏览器渲染进程(Renderer进程/浏览器内核):内部是多线程的,默认每个Tab页面一个进程,互不影响
- 页面渲染、脚本执行、事件处理
- 第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
浏览器多进程的优势:
如果浏览器是单进程,那么某个Tab页崩溃了,就影响了整个浏览器,体验有多差;同理如果是单进程,插件崩溃了也会影响整个浏览器。
渲染进程:
页面渲染、JS的执行、事件循环等,都在这个进程内进行。
浏览器的渲染进程是多线程的:
- GUI渲染线程
- 负责渲染浏览器界面,解析HTML、CSS、构建渲染树、布局和绘制等
- 当界面需要重绘或由于某种操作引发回流时,该线程就会执行
- GUI渲染与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行
- 这是因为js是可以操作dom的,如果在修改这些元素属性的同时渲染界面,那么渲染线程前后获得的元素数据就可能不一致了
- JS引擎线程
- 也称为JS内核,负责处理JS脚本程序,如chrome的V8引擎
- 负责解析JS脚本、运行代码,JS引擎一直等待任务队列中任务的到来,然后加以处理
- 一个Tab页(Renderer进程)中无论什么时候都只有一个JS线程在运行JS程序
- 由于GUI渲染线程和JS引擎线程是互斥的,所以如果JS执行的时间过长,这样就会导致页面的渲染不连贯,导致页面渲染加载阻塞
- 事件触发线程
- 用来控制事件循环
- 当JS引擎执行代码块如setTimeOut时(也可以来自浏览器内核的其他进程,如鼠标点击/Ajax异步请求等),会将对应任务添加到事件线程中
- 当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理
- 由于JS引擎的单线程,这些事件都必须排队等待JS引擎的处理
- 定时触发器线程
- setInterval与setTimeout所在的线程
- 浏览器定时计数器并不是由JavaScript引擎计数的,(因为JavaScript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确)
- 异步HTTP请求线程

Browser进程和浏览器内核(Renderer进程)的通信过程
如果自己打开任务管理器,然后打开一个浏览器,就可以看到:任务管理器中出现了两个进程(一个是主控进程,一个则是打开Tab页的渲染进程)
- Browser进程收到了用户请求,首先需要获取页面内容。随后将该任务通过RendererHost接口传递给Rederer进程
- Renderer进程的Renderer接口收到消息,简单解释后交给渲染线程,然后开始渲染,期间可能需要Browser进程获取资源和需要GPU进程来帮助渲染。最后将结果传递给Browser进程
- Browser进程接收到结果并将结果绘制出来
WebWorker,JS的多线程?
解决js执行时间过长导致的页面阻塞,增强js对cpu密集型计算的能力
- 创建Worker时,JS引擎向浏览器申请开一个子线程(这个子线程是浏览器开的,完全受主线程控制,而且不能操作dom)
- JS引擎线程与worker线程间通过特定的方式通信
- 有非常耗时的计算工作时,可以单独开一个Worker线程,这样里面不管如何翻天覆地都不会影响JS引擎主线程,只等到计算出结果后,将结果通信给主线程
而且注意下,JS引擎是单线程的,这一点的本质仍然未改变,Worker可以理解是浏览器给JS引擎开的外挂,专门用来解决那些大量计算问题。
CSS加载阻塞?
这里是指的在头部引入的情况(link标签)
CSS是由单独的下载线程异步下载的:
- CSS加载不会阻塞dom树解析,异步加载时dom照常构建
- 但会阻塞render树的渲染,因为render树需要cssom
原因:
因为你加载css的时候,可能会修改下面DOM节点的样式,如果css加载不阻塞render树渲染的话,那么当css加载完之后,render树可能又得重新重绘或者回流了,这就造成了一些没有必要的损耗。所以干脆就先把DOM树的结构先解析完,把可以做的工作做完,然后等你css加载完之后,在根据最终的样式来渲染render树,这种做法性能方面确实会比较好一点。
浏览器渲染过程
例子:
dom和cssom的构建
简单来说就是把HTML文档和样式表都转换为树状结构,因为HTML和Css都是嵌套的,浏览器在计算任何节点的样式时,它会从适用于该节点的最通用(顶层)的规则开始计算。比如说要计算的节点是body元素的子元素,它就会先应用body的样式,之后会一层一层进行递归该过程,最终得到该节点的样式。
HTML Parser:主线程上的同步解析过程,遇到img等资源标签会触发异步加载,但不会阻塞解析
Css Parse和Dom Parse的并行关系?
如果Css是写在style标签中的,那么在chrome中style标签会被HTML Parse来解析,此时Css Parse和Dom Parse就不是并行的。
但是大多数情况下,Css文件都会使用外部链接的方式进行引入,当使用link标签引入Css文件时,由于Cssom的生成时机并不会影响DomTree的改变,因此当HTML Parse遇到link标签的stylesheet时并不会等待stylesheet下载并解析完毕后才解析后续dom,而是在网络进程加载style脚本的同时可以继续去解析后续dom,这时dom和cssom就是一个并行关系/非阻塞关系。
所以,通常我们所说 Dom 和 Cssom 生成的非阻塞更多的是指加载样式脚本并不会阻塞后续 Dom 解析(这里的非阻塞更多相对于 JS 文件来说,因为同步 JS 文件的加载是会阻塞后续 Dom 构建的),而主线程解析生成 cssom 的过程一定是会和 parse Html 抢占主线程资源的(主线程并不会同时 parse Html 以及同时 parse stylesheet)。
生成渲染树
上述过程中基于HTML和CSS构建了dom树和cssom树,此时两棵树都还是互相独立的两个树状对象。
上述过程结束后,浏览器会将两个Tree进行合并,最终组成一个具有所有可见节点样式和内容的render tree。
- 一些脚本标签、元标签等节点是不可见的,由于它们未反映在页面的呈现中所以会被被省略。
- 同时对于一些通过 CSS 隐藏的节点,也会从渲染树中省略。比如,上述 HTML 中的 span 节点在上面的例子中会在渲染树中丢失,因为它明确的设置了 “display: none” 属性。
visibility: hidden
不同于display: none
. 前者使元素不可见,但元素在布局中仍然占据空间(渲染为空框),而后者display: none
表示将元素从渲染树中完全移除,使元素不可见从而不是布局的一部分。
最终,经过上述步骤浏览器会组装 DomTree 和 CssomTree 成为 RenderTree,RenderTree 中包含屏幕上所有可见内容的内容和样式信息
布局
render tree构建完成后,就会进入布局Layout阶段了。此时浏览器已经明确地清楚哪些节点应该被渲染到页面上,同时也获得了可见节点的样式,但是浏览器还没有计算出每个节点在对应设备上确切的位置和大小,这一步就是Layout阶段应该做的事。
布局确定了树中所有节点的宽度、高度和位置信息。
绘制
渲染树和布局完成后,像素就可以被绘制在屏幕上。在绘制阶段,浏览器将布局阶段计算的每个 frame 转为屏幕上实际的像素点。包括将元素的可见部分进行绘制,比如文本、颜色、边框、阴影、替换元素等。
js阻塞?
内联 js:
- 对于内联脚本,JS不存在加载,但是当浏览器对HTML进行解析时解析到script脚本之后,会将主线程交给JS引擎线程去执行js,这样GUI渲染线程就被JS抢走了,自然无法进行渲染了
- 因此JS的解析和执行一定会阻塞页面的渲染
外链 js:
- JS脚本在顶部
- 将外部标签卸载head标签之后是会阻塞后续DOM渲染的
- 解析到script标签,开始下载资源,渲染阻塞
- 停止dom解析
- 执行js代码
- js执行完成恢复解析,此时才开始构建渲染树
- JS脚本在底部
- 在执行js之前浏览器已经进行了首次绘制,此时外部脚本的加载和执行只是会影响后续dom的解析的渲染,对于脚本之前的dom并不会阻塞它的解析以及渲染
async 和 defer:
- async
- 浏览器解析到
<script async>
时,会并行下载脚本(不阻塞 DOM 解析) - 脚本下载完成后立即暂停 DOM 解析,执行脚本,执行完毕后再恢复解析
- 虽然下载的时候不阻塞 DOM 解析,但是执行的时候会阻塞
- 多个
async
脚本的执行顺序与它们在文档中的顺序无关,取决于下载完成的先后顺序 - 应用场景:独立脚本,如广告脚本等,不依赖 DOM 或其他的脚本
- defer
- 浏览器解析到
<script defer>
时,会并行下载脚本(不阻塞 DOM 解析) - 脚本的执行会被推迟到 DOM 解析完成之后(
DOMContentLoaded
事件触发前) - 脚本的下载和执行都不会阻塞 DOM 解析
- 多个
defer
脚本按文档中的顺序执行,即使后面的脚本先下载完成 - 应用场景:依赖 DOM 或其他脚本的代码(如需要操作 DOM 的库)
- 浏览器内核
- 浏览器网络线程池负责下载脚本,与主线程(负责解析/渲染)并行
TS单例
有一个实例之后,用new就不能创建一个新实例了
- Author:orangec
- URL:orange’s blog | welcome to my blog (clovy.top)/article/71de5209-4da7-42f0-84d1-478d63307f8f
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!