浏览器
描述出入URL到页面呈现的完整过程
解析URL:用户在浏览器地址栏中输入要访问的URL(统一资源定位符),浏览器需要检查它的合法性,如果是不合法的URL则传给搜索引擎进行搜索,如果是合法URL则需要检查是否含有非法字符,若有非法字符则需要进行转义。
域名解析:浏览器通过DNS(域名系统)将域名解析为对应的IP地址,以便确定要访问的服务器位置。
建立TCP连接:浏览器与服务器之间通过TCP(传输控制协议)建立连接,确保可靠的数据传输。
发起HTTP请求:浏览器向服务器发送HTTP请求,请求包括请求的资源类型(如HTML、CSS、JavaScript等)以及其他相关信息。
服务器处理请求:服务器接收到请求后,根据请求的资源类型和路径,处理请求并准备响应数据。
服务器返回响应:服务器将处理后的响应数据(如HTML页面、CSS样式表、JavaScript代码等)发送回浏览器。
浏览器接收响应:浏览器接收到服务器返回的响应数据,开始解析和加载页面资源。
构建DOM树:浏览器根据HTML内容构建DOM(文档对象模型)树,表示页面的结构。
构建CSSOM树:浏览器解析CSS样式表,构建CSS对象模型(CSSOM)树,表示页面的样式信息。
合并DOM和CSSOM:浏览器将DOM树和CSSOM树合并,生成渲染树(Render Tree),确定每个节点在页面上的位置和样式。
页面布局:浏览器根据渲染树计算每个节点在页面中的确切位置和大小,进行页面布局。
页面绘制:浏览器根据页面布局信息,将页面内容绘制到屏幕上,呈现给用户。
执行JavaScript:如果页面中包含JavaScript代码,浏览器会执行JavaScript代码,可能会修改页面内容或交互行为。
加载其他资源:页面中可能包含其他资源(如图片、视频、字体等),浏览器会继续加载这些资源并显示在页面上。
页面呈现完成:页面所有内容加载完成后,页面呈现完成,用户可以与页面进行交互。
JS文件放置在HTML文档不同位置的影响
将<script>
放置在<head>
中:
优点:可以确保所有的JavaScript代码在页面内容加载前执行,确保代码能够访问到页面中的所有元素。也有利于代码的结构和维护,可以集中管理所有的JavaScript代码。
缺点:JavaScript文件在加载和执行时会阻塞页面的渲染,可能导致页面加载速度变慢,用户看到空白页面的时间变长。
将<script>
放置在<html>
底部:
优点:可以让页面内容先加载完毕再加载和执行JavaScript,加快页面的初始加载速度,提升用户体验。避免JavaScript阻塞页面渲染,使页面更快地呈现给用户。
缺点:可能会导致页面在加载过程中出现页面元素闪烁或布局错乱的情况,因为JavaScript在页面加载后才执行,可能会导致页面重绘。
什么是回流(Reflow)?如何触发它?
回流(Reflow)是浏览器重新计算元素在页面上的位置和大小的过程。当页面布局发生变化时(如添加、删除、修改元素、修改元素样式、改变窗口大小等),浏览器会重新计算元素的几何属性,这个过程就是回流。
回流是一种比较昂贵的操作,因为它会导致整个页面的重新布局和重绘,影响页面的性能。简而言之,回流一定会触发重绘。因此,尽量减少回流的次数是优化页面性能的重要一步。
以下是一些常见触发回流的操作:
修改DOM结构:如添加、删除、移动DOM元素。
修改元素的尺寸、位置、内容:如修改元素的宽度、高度、内外边距、边框、字体大小等。
计算样式:获取某些属性(如offsetTop、offsetLeft、offsetWidth、offsetHeight、scrollTop、scrollLeft等)会导致回流。
改变窗口大小:当浏览器窗口大小改变时,页面布局需要重新计算,会触发回流。
为了减少回流的次数,可以采取以下优化措施:
避免直接操作样式:最好一次性修改元素的样式,而不是逐个属性修改。
使用文档片段(Document Fragment):对多个DOM操作进行批量处理,减少回流次数。
避免频繁访问计算样式的属性:尽量将这些属性缓存起来,避免多次访问。
使用CSS动画代替JavaScript动画:CSS动画通常会优化处理,减少回流次数。
通过避免不必要的回流操作,可以提高页面的性能和用户体验。
什么是重绘(Repaint)? 如何触发它?
重绘(Repaint)指的是当元素样式发生变化,但不影响其在文档流中的位置时,浏览器会重新绘制该元素的过程。在重绘过程中,浏览器会根据新的样式信息重新绘制元素的外观,但不会影响元素的位置和大小。
触发重绘的情况包括:
样式变化:当元素的样式属性(如颜色、背景等)发生变化时,会触发重绘。
伪类激活:当元素的伪类(如:hover)被激活时,会触发重绘。
内容变化:当元素的文本内容发生变化时,可能会触发重绘。
其他情况:例如调整元素透明度、改变文字颜色等。
与回流不同的是,重绘不涉及元素的尺寸、位置或布局的改变,只是重新绘制元素的外观。因此,重绘的性能开销通常比回流要小,但在大规模页面中频繁触发重绘也会影响页面的性能。
什么是浏览器的同源策略?为什么会有同源策略?
浏览器的同源策略(Same-Origin Policy)是一种安全机制,用于限制一个网页文档或脚本如何与另一个源(域名、协议、端口都相同)的资源进行交互。同源策略要求网页只能与同一源的资源进行交互,而不能与不同源的资源进行直接交互。
同源策略的原因和作用包括以下几点:
保护用户隐私:同源策略可以防止恶意网站窃取用户在其他网站上的信息,保护用户的隐私和安全。
防止跨站脚本攻击(XSS):同源策略可以防止恶意脚本在一个站点上执行,并访问另一个站点的敏感数据,从而防止跨站脚本攻击。
防止跨站请求伪造(CSRF):同源策略可以防止恶意网站伪造用户请求另一个站点的请求,从而防止跨站请求伪造攻击。
保护用户数据安全:同源策略可以确保用户在一个网站输入的数据不会被其他网站恶意获取,保护用户数据的安全性。
同源策略限制了不同源之间的直接交互,但可以通过跨域资源共享(CORS)等机制来允许跨域资源的访问。这种限制是为了保护用户和网站的安全,防止恶意行为对用户数据和系统造成损害。
描述下开发过程中遇到的跨域问题?为什么会产生跨域?如何解决?
产生跨域的原因: 同源策略。
跨域问题:
异步请求跨域。
嵌入跨域资源: 通过
<script>
标签加载不同域下面的JS文件跨域写入cookie
跨域iframe通信
解决方式:
JSONP(JSON with Padding):通过
<script>
标签加载包含回调函数的JSON数据。CORS(Cross-Origin Resource Sharing):服务器端设置响应头,允许跨域请求。
代理:在同源域下设置代理服务器转发请求。
WebSocket:使用WebSocket协议进行跨域通信。
跨文档消息通信(PostMessage):在不同域之间传递数据。
修改服务器配置:在服务器端配置允许跨域请求。
什么是正向代理和反向代理?都有什么作用?
正向代理(Forward Proxy:
作用:正向代理位于客户端和目标服务器之间,代理客户端向目标服务器发起请求,并将目标服务器的响应返回给客户端。客户端向代理服务器发送请求,然后由代理服务器转发请求给目标服务器,隐藏了客户端的真实IP地址。
应用场景:用于访问受限制的内容,保护客户端隐私,加速访问速度等。示例:vite中开发服务器设置代理,VPN等等。
反向代理(Reverse Proxy):
作用:反向代理位于客户端和多个目标服务器之间,代理目标服务器处理客户端的请求,隐藏了服务器的真实IP地址。客户端向反向代理发送请求,然后由反向代理根据负载均衡等策略将请求转发给后端的多个目标服务器。
应用场景:用于负载均衡、提高安全性、缓存静态内容、隐藏后端服务器等。示例:公司内部部署的网站通常会使用反向代理来处理请求,以实现负载均衡和隐藏真实服务器。
什么是浏览器的事件循环机制?它和Nodejs中的事件循环机制有什么区别?
浏览器中的事件循环:首先脚本本身的执行就是一个宏任务,在执行同步代码时遇到微任务就将它加入微任务队列(FIFO),遇到宏任务就加入宏任务队列(FIFO),当本次脚本的同步代码执行完毕(可以看作是一个宏任务结束),就查看微任务队列并依次执行,执行一个微任务就移除微任务队列直到微任务队列执行完毕;接着查看宏任务队列,依次执行。整体执行效果就是一个循环,宏任务->微任务 -> 宏任务。
如果在一轮事件循环中,微任务和宏任务队列都为空,那么主线程会进入idle状态(休眠),此时会保持轮询事件循环,等待响应新的事件(用户输入交互,定时器到期)。
区别:
浏览器的事件循环是根据HTML标准实现的,而nodejs中的事件循环是基于libuv实现的。libuv是一个C语言实现的高性能解决单线程非阻塞异步 I/O 的开源库,它本质上是对常见操作系统底层异步I/O操作的封装,nodejs底层就是调用它的API。
浏览器中的事件循环和Nodejs中的事件循环都将异步任务划分为宏任务和微任务:
- 浏览器微任务: Promise.then() 、 MutationObserver。
- 浏览器宏任务: setTimeout/setInterval、 script(整体代码) 、 UI事件 、Postmessage 、 MessageChannel。
- NodeJS微任务: Promise.then、process.nestTick。
- NodeJS宏任务: setTimeout、setInterval、 setImmediate、script(整体代码)、 I/O 操作。
什么是垃圾回收机制?
浏览器的垃圾回收机制是指浏览器在运行过程中负责自动管理内存的一种机制,用于检测不再使用的内存块,并将其释放,以便其他程序使用。在JavaScript中,垃圾回收机制主要用于回收不再使用的对象,防止内存泄漏。
浏览器的垃圾回收机制通常包括以下几种策略:
标记-清除(Mark-and-Sweep):这是最常见的垃圾回收算法之一。它通过标记不再使用的对象,然后清除这些对象来释放内存。在这个过程中,垃圾回收器会遍历所有对象,并标记那些仍然可达的对象,然后清除那些未被标记的对象。
引用计数(Reference Counting):这种方法会跟踪每个对象被引用的次数。当对象的引用计数变为0时,即没有任何引用指向该对象时,垃圾回收器会释放该对象的内存。然而,这种方法容易出现循环引用的问题,导致内存泄漏。
分代回收(Generational Garbage Collection):这是一种更高级的垃圾回收策略,根据对象的存活时间将内存分为不同的代。通常将内存分为新生代和老年代,根据对象的存活时间将其分配到不同的代中进行垃圾回收,以提高效率。
JS哪些操作会引起内存泄漏?如何避免?
JavaScript中可能导致内存泄漏的一些常见操作包括:
意外的全局变量:如果意外地将变量声明为全局变量,而不是局部变量,这些变量可能会一直存在于内存中而不被释放。
未清理的定时器:如果定时器没有被清理,它们会持续运行并占用内存。
闭包:闭包中的变量会一直存在于内存中,直到闭包不再被引用,但如果闭包被错误地保留,可能会导致内存泄漏。
DOM引用:保留对DOM元素的引用,即使这些元素已经不再需要,也会导致内存泄漏。
事件监听器:未正确移除不再需要的事件监听器也可能导致内存泄漏。
为了避免内存泄漏,可以采取以下措施:
正确使用变量作用域:避免意外的全局变量,确保变量在合适的作用域内声明。
及时清理定时器:确保不再需要的定时器被正确清理。
合理使用闭包:确保不再需要的闭包被正确释放,避免保留不必要的引用。
合理管理DOM引用:在不需要时及时移除对DOM元素的引用。
正确移除事件监听器:当不再需要时,记得移除事件监听器。
使用工具进行内存泄漏检测:可以使用浏览器开发者工具或第三方工具来检测内存泄漏问题。
通过以上方法,可以帮助避免JavaScript中常见的内存泄漏问题,提高代码的性能和稳定性。
浏览器的并发请求有什么限制?
同一域名下的并发限制: 浏览器对同一域名下的并发请求有限制,通常为6-8个。这意味着在同一时间内,浏览器最多可以同时发起6-8个针对同一域名的请求,超过这个数量的请求会被排队等待。
单个域名下的并发连接数限制:浏览器对单个域名下的并发连接数也有限制,通常为6-8个。这意味着即使是不同路径下的资源请求,如果它们指向同一域名,也会受到并发连接数的限制。
HTTP/1.1的管线化(Pipeline)限制:在HTTP/1.1中,管线化允许在同一个TCP连接上发送多个HTTP请求,但浏览器对管线化的支持有限,可能会导致部分请求无法并行处理。
描述浏览器解析HTML并加载CSS和Javascript的过程?
解析HTML,构建DOM树。
解析CSS,构建CSSOM树。
合并DOM树和CSSOM树,生成Render树。
布局:根据Render树信息计算没一个节点位置和大小等到Layout树。
分层:通过对Layout树划分层次,便于后续对某个节点修改时仅对所在层进行处理,提升效率。
绘制:描述每一层的像素信息和如何绘制(光栅化),然后将绘制信息交给合成线程,合成线程先对每个图层进行分块,将其划分成更小的区域,最后将不同图层合成页面显示。
预解析
浏览器在解析HTML之前会开启一个预解析线程,提前下载HTML中的CSS和JS文件。当解析HTML遇到<link>
且外部CSS还没下载好,主线程不会等待,继续解析HTML。这就是为什么CSS不会阻塞HTML解析的根本原因。当解析HTML遇到<script>
且外部JS还没下载好,主线程会等待JS下载并执行完毕才能继续解析,这是因为JS中可能会操作DOM树,这也是为什么JS会阻塞HTML解析的根本原因。预解析结束后会将CSSOM树返回给主线程。
window load 和 document ready的区别?
window.load事件是再整个页面以及所有依赖资源例如样式表和图片等都加载完时触发。
JQuery中的document ready事件是在DOM树加载完时触发,不必等待其他依赖资源的加载。
clientWidth/clientHeight、offsetWidth/offsetHeight分别代表什么意思,有什么区别?
clientWidth
和clientHeight
表示元素内部的宽高,不包括边框、外边距、滚动条。offsetWidth
和`offsetHeight 表示元素的整体宽高,包括内容区域、内边距、边框,但不包括外边距。