常见的浏览器内核有哪些?
常见的浏览器内核有以下几种:
Trident(IE内核): Trident是由Microsoft开发的浏览器排版引擎,最初用于Internet Explorer(IE)浏览器。它在过去的IE版本中被广泛使用,但在现代浏览器中已经被EdgeHTML引擎所取代。
Gecko: Gecko是由Mozilla基金会开发的浏览器引擎,用于Mozilla Firefox浏览器及其他相关项目。它是一个开源引擎,支持多平台,并且在安全性和可扩展性方面有着良好的声誉。
WebKit: WebKit是一个开源的浏览器引擎,最初由Apple开发,用于Safari浏览器。它具有快速的渲染速度和良好的页面兼容性,因此被许多其他浏览器所采用或基于,包括Google Chrome的早期版本。
Blink: Blink是由Google基于WebKit引擎分叉而来的浏览器引擎。它用于Google Chrome浏览器和Opera浏览器。Blink引擎的优势在于速度、稳定性和安全性,并且支持现代Web标准。
EdgeHTML(Chakra): EdgeHTML是由Microsoft开发的浏览器引擎,最初用于Microsoft Edge浏览器。它取代了旧版的Trident引擎,并带来了更好的性能和兼容性。然而,自2020年起,Microsoft宣布将Edge浏览器转向使用Chromium作为底层引擎。
这些浏览器内核在不同的浏览器中使用,它们的差异在于性能、渲染方式和对Web标准的支持程度。开发人员在进行网页开发时,需要考虑这些不同的内核特性和兼容性,以确保网页在各种浏览器中都能正确显示和运行。
说一说从输入URL到页面呈现发生了什么?
当我们在浏览器中输入一个URL并按下回车键时,以下是从输入URL到页面呈现的基本过程:
URL解析(URL Parsing):浏览器解析输入的URL,提取出协议(例如:HTTP、HTTPS)、主机名(例如:
www.example.com
)和路径(例如:/page
)等信息。DNS解析(DNS Resolution):浏览器将主机名(例如:
www.example.com
)发送到本地DNS服务器,本地DNS服务器会查询域名的IP地址,并将其返回给浏览器。建立TCP连接(TCP Connection):浏览器使用HTTP协议建立与Web服务器的TCP连接。这个过程涉及三次握手,即客户端发送SYN(同步)包,服务端返回SYN-ACK(同步-确认)包,最后客户端发送ACK(确认)包。
发起HTTP请求(HTTP Request):一旦与服务器建立了TCP连接,浏览器向服务器发送HTTP请求,包括请求行、请求头和请求体。请求行包含请求方法(例如:GET、POST)、请求的URL和HTTP协议的版本。
服务器处理请求:Web服务器接收到HTTP请求后,根据请求的URL和其他相关信息,处理请求并生成响应。
接收响应(HTTP Response):服务器将生成的HTTP响应发送回浏览器。响应包括响应状态码(例如:200表示成功、404表示未找到等)、响应头和响应体。
浏览器渲染:一旦浏览器接收到响应,它开始解析响应的HTML内容,并构建DOM树(文档对象模型)来表示页面的结构。同时,浏览器还会执行CSS解析、构建渲染树和布局等操作,最终将页面内容显示在屏幕上。
下载资源:在渲染过程中,浏览器会解析HTML文档中的其他资源链接,如CSS文件、JavaScript文件、图像等,并发起额外的HTTP请求来下载这些资源。
执行JavaScript:如果HTML文档中包含JavaScript代码,浏览器会执行这些脚本。JavaScript可以修改DOM树、处理用户交互、发送异步请求等操作。
页面呈现:当浏览器完成渲染、执行JavaScript和下载所有资源后,页面的呈现过程完成。用户可以与页面进行交互,并查看最终的网页内容。
总结起来,从输入URL到页面呈现的过程包括URL解析、DNS解析、建立TCP连接、发起HTTP请求、服务器处理请求、接收响应、浏览器渲染、下载资源、执行JavaScript和页面呈现等步骤。每个步骤都涉及不同的网络协议和浏览器引擎功能,最终将网页内容展示给用户。
浏览器的主要组成部分有哪些?
浏览器是一个复杂的软件应用程序,由多个组成部分协同工作来实现网页浏览和交互。以下是浏览器的主要组成部分:
用户界面(User Interface):用户界面是用户与浏览器进行交互的部分,包括地址栏、导航按钮(前进、后退)、书签管理、菜单等。用户界面通常由浏览器的前端开发人员设计和实现。
浏览器引擎(Browser Engine):浏览器引擎负责解析并渲染HTML、CSS和JavaScript等网页内容。它可以分为两个主要部分:渲染引擎(用于解析和呈现HTML、CSS)和JavaScript引擎(用于解析和执行JavaScript代码)。
渲染引擎(Rendering Engine):渲染引擎负责将HTML和CSS等网页内容解析为可视化的页面。常见的渲染引擎包括WebKit(用于Safari浏览器)、Blink(用于Chrome和Opera浏览器)和Gecko(用于Firefox浏览器)。
JavaScript引擎(JavaScript Engine):JavaScript引擎负责解析和执行网页中的JavaScript代码。不同浏览器使用不同的JavaScript引擎,例如V8引擎(用于Chrome浏览器)、SpiderMonkey引擎(用于Firefox浏览器)和JavaScriptCore引擎(用于Safari浏览器)等。
网络(Networking):网络模块负责处理网络请求和响应,包括HTTP请求、DNS解析、TCP/IP连接等。它使浏览器能够从服务器下载网页内容和其他资源。
数据存储(Data Storage):数据存储模块用于在浏览器中存储数据,包括Cookie、本地存储(localStorage、sessionStorage)和IndexedDB等。这些存储机制允许网页在客户端存储和检索数据。
插件(Plugins):插件是一种扩展浏览器功能的组件,允许浏览器加载和运行第三方插件。常见的插件包括Adobe Flash Player、Java插件等。
安全模块(Security Module):安全模块负责保护用户的隐私和安全。它包括对HTTPS的支持、恶意软件防护、弹出窗口拦截等安全功能。
JavaScript API(JavaScript APIs):JavaScript API提供了丰富的功能和接口,允许网页通过JavaScript与浏览器进行交互。例如,操作DOM、处理用户输入、发送AJAX请求等。
以上是浏览器的主要组成部分,它们共同协作以提供用户友好的网页浏览和交互体验。不同的浏览器可能在实现和功能上有所不同,但这些基本组件是浏览器的核心。
浏览器是如何解析代码的?
浏览器解析代码的过程涉及到渲染引擎(Rendering Engine)和JavaScript引擎(JavaScript Engine)。以下是浏览器解析代码的基本流程:
HTML解析:渲染引擎开始解析HTML代码,构建文档对象模型(DOM)。它将HTML标记解析为DOM节点,包括元素、属性和文本内容等。解析过程中,渲染引擎会处理元素的嵌套关系、属性值等,构建出完整的DOM树。
CSS解析:渲染引擎解析CSS代码,构建样式规则和计算样式值。它会处理CSS选择器,匹配DOM节点,并计算出最终应用在节点上的样式。解析过程中,渲染引擎还会处理样式的继承、层叠等规则。
DOM树构建:渲染引擎根据HTML和CSS解析结果,构建DOM树。DOM树表示了网页的结构和内容,它由DOM节点和它们之间的关系组成。
渲染树构建:渲染引擎根据DOM树和CSS解析结果,构建渲染树(Render Tree)。渲染树是DOM节点的可视化表示,它包含需要显示在屏幕上的元素和样式信息,同时忽略了不需要显示的元素(如隐藏元素)。
布局(Layout):渲染引擎根据渲染树的信息,计算每个元素在屏幕上的位置和大小,即进行布局或重排。这个过程确定了元素在页面中的准确位置,以便后续的绘制。
绘制(Painting):渲染引擎根据布局结果,将渲染树中的元素绘制到屏幕上,形成最终的可视化页面。绘制过程通常包括将元素转换为像素、应用样式、处理透明度、生成阴影等操作。
对于JavaScript代码的解析和执行,涉及到JavaScript引擎。以下是JavaScript代码解析和执行的基本流程:
解析(Parsing):JavaScript引擎将JavaScript代码解析成抽象语法树(AST)。解析过程涉及词法分析(将代码转化为词法单元)和语法分析(根据语法规则构建抽象语法树)等步骤。
编译(Compilation):解析后,生成的抽象语法树会被编译成可执行代码。编译过程包括优化、字节码生成等步骤,以提高代码执行效率。
执行(Execution):编译后的代码被JavaScript引擎执行。引擎按照代码的执行顺序逐行执行,执行过程中会操作DOM、修改样式、处理事件、发送网络请求等。
在执行过程中,渲染引擎和JavaScript引擎会相互交互。例如,JavaScript代码可能通过操作DOM树来修改页面内容,或者通过修改样式来改变元素的外观。这种交互使得网页能够实现动态和交互性的功能。
总结起来,浏览器解析代码的过程涉及HTML和CSS的解析、DOM树的构建、渲染树的构建、布局、绘制,以及JavaScript的解析、编译和执行等步骤。这些步骤协同工作,最终将网页内容呈现给用户。
DOMContentLoaded与load的区别?
DOMContentLoaded
和load
都是JavaScript中与页面加载相关的事件,它们有以下区别:
DOMContentLoaded事件:
- 触发时机:
DOMContentLoaded
事件在页面文档解析完成并构建了完整的DOM树后触发,此时页面的HTML结构已经可以进行访问和操作。 - 触发条件:当所有必要的DOM内容(如标记、文本和元素)都已经解析完毕时触发,不考虑外部资源的加载状态(如图片、样式表等)。
- 适用情况:一般用于执行与DOM操作相关的JavaScript代码,如修改DOM元素、绑定事件处理程序等。它的触发时机比
load
事件更早,因此可以提供更快的用户体验,因为不需要等到所有外部资源加载完毕。
load事件:
- 触发时机:
load
事件在整个页面及其所有相关资源(包括外部样式表、脚本、图片等)都已经加载完毕后触发,此时页面已经完全呈现给用户。 - 触发条件:当整个页面及其相关资源都已经加载完成时触发,包括DOM树构建完成、外部资源下载完毕、样式表应用、图片加载等。
- 适用情况:一般用于执行需要等待页面完全加载的JavaScript代码,如处理图片尺寸、计算页面元素位置等。由于
load
事件的触发时机较晚,因此它适用于那些需要等待页面所有资源加载完毕后才能执行的操作。
总结:
DOMContentLoaded
事件在DOM解析完成后触发,适用于处理与DOM操作相关的代码。load
事件在页面及其所有相关资源加载完成后触发,适用于处理需要等待页面完全加载的操作。DOMContentLoaded
事件触发时机较早,可以提供更快的用户体验,而load
事件触发时机较晚,适合处理依赖于外部资源的操作。
浏览器重绘域重排的区别?
浏览器中的重绘(Repaint)和重排(Reflow)都涉及到网页的布局和渲染,但它们的操作对象和影响范围有所不同。
重绘(Repaint): 重绘指的是当元素样式的可视属性发生改变(如颜色、背景色、边框等),但并不影响其布局的情况下,浏览器会重新绘制(repaint)这些元素的可视外观,以便更新显示。重绘操作只会更新元素的视觉呈现,而不会改变页面的布局和元素的位置。
重绘的特点:
- 只涉及元素可视样式的改变,不改变布局。
- 重绘操作消耗的资源相对较少,性能开销较小。
- 重绘不会引起其他元素的重新布局。
重排(Reflow): 重排指的是当页面布局发生改变,导致元素的大小、位置、结构等属性发生变化时,浏览器需要重新计算元素的几何属性和页面的布局,并重新渲染页面。重排操作会涉及到整个页面或局部区域的重新布局和渲染,因此性能开销相对较大。
重排的特点:
- 涉及元素的布局属性改变,如尺寸、位置、内容等。
- 重排操作会触发元素的重新计算、布局和绘制,涉及到多个阶段的处理。
- 重排操作会引起其他元素的重新布局和渲染,可能导致性能下降。
重绘和重排的关系: 重排操作往往会导致重绘,因为重新布局后,元素的可视样式可能会发生变化,需要进行重绘以更新显示。然而,重绘不一定会引起重排,因为只有布局相关的属性发生变化时,才会触发重排操作。
优化建议: 由于重排操作的性能开销较大,频繁的重排和重绘会降低网页的性能。为了优化页面的渲染性能,可以采取以下策略:
- 减少对布局属性的访问和修改,尽量避免不必要的布局变化。
- 使用CSS的
transform
和opacity
等属性进行动画效果,而不是影响布局的属性。 - 批量修改样式,避免多次单独修改样式。
- 使用CSS3硬件加速(例如使用
transform
属性)可以减少重排和重绘的次数。 - 对于需要频繁操作的DOM元素,可以将其脱离文档流,进行操作后再重新插入文档流,以减少重排的影响。
通过合理的优化和避免不必要的重排和重绘,可以提高网页的性能和用户体验。
为什么JS是单线程的?
JavaScript是单线程的设计,这意味着它一次只能执行一个任务,而不是同时执行多个任务。这设计主要有以下原因:
简单性和可靠性:单线程模型使得JavaScript的设计和实现更加简单,减少了并发编程所带来的复杂性。这使得语言更容易学习和使用,并且减少了潜在的并发问题,提高了可靠性。
安全性:在Web浏览器环境中,JavaScript主要用于操作DOM、处理用户交互和执行网络请求等任务。如果JavaScript是多线程的,那么在多个线程同时操作DOM等共享资源时,可能会引发竞态条件(Race Condition)等并发问题,导致不可预测的结果。通过将JavaScript限制为单线程,可以避免这些潜在的安全问题。
事件驱动模型:JavaScript在浏览器中常用于响应用户的交互事件,如点击、滚动、键盘输入等。单线程模型可以简化事件处理逻辑,确保事件的处理顺序是有序的,避免了多个线程之间的同步和竞争问题。
尽管JavaScript本身是单线程的,但是现代的浏览器环境提供了一些异步编程的机制,如回调函数、Promise、async/await等,使得JavaScript能够处理异步任务,如网络请求、定时器等,而不会阻塞主线程的执行。这样可以在单线程的基础上实现并发和响应性,提供更好的用户体验。
需要注意的是,虽然JavaScript是单线程的,但是浏览器环境本身是多线程的,包括渲染线程、网络线程、事件线程等,在处理一些耗时的任务时,浏览器可以利用这些额外的线程来提高性能和并发能力。但是这些线程并不能直接操作JavaScript对象和DOM,它们通过与JavaScript主线程的协作来实现并发处理。
CSS加载会阻塞DOM吗?
在默认情况下,CSS加载不会阻塞DOM的解析。浏览器在解析HTML文档时,遇到外部CSS文件的引用会发起异步的网络请求去下载CSS文件,但它不会阻塞DOM树的解析和构建。这意味着浏览器会继续解析HTML,并构建DOM树,即使CSS文件还未完全下载和解析完成。
然而,当浏览器解析到<link>
标签或内联<style>
标签时,会触发CSS的解析和应用过程。在这个阶段,浏览器会停止DOM的解析,等待CSS文件下载完成并进行解析,然后将样式应用到已经解析好的DOM元素上。这个过程称为"渲染树的构建阶段"。
所以,尽管CSS加载不会直接阻塞DOM的解析,但它可能会延迟DOM的渲染和显示。特别是当有大量的CSS规则和复杂的选择器时,浏览器需要花费更多的时间去解析CSS,从而延迟DOM的渲染。这可能导致一些闪烁或延迟显示的现象,特别是在初始加载时。
为了改善网页的加载性能和用户体验,可以采取以下策略:
- 尽量减少页面中的CSS文件数量和大小,合并和压缩CSS文件。
- 将关键CSS(如页面的核心样式)内联到HTML中,以避免额外的网络请求和等待时间。
- 使用媒体查询等技术,将不必要的CSS规则延迟加载或异步加载。
- 使用CSS的
rel="preload"
属性或JavaScript进行异步加载CSS,以提前获取并缓存CSS文件,减少等待时间。
通过优化CSS的加载和应用方式,可以加快页面的渲染速度,提高用户的感知体验。
JS会阻塞页面吗?
JavaScript在执行过程中可以阻塞页面的渲染和响应,具体取决于JavaScript代码的执行方式和执行时间。
阻塞页面的情况:
同步执行:当浏览器遇到同步的JavaScript代码时,会阻塞页面的渲染和响应,直到该代码执行完成。这会导致页面的加载和交互被暂停,用户可能会感觉到页面的卡顿或无响应。特别是在JavaScript代码较长或执行时间较长时,影响更为明显。
JavaScript文件加载:当浏览器遇到外部的JavaScript文件(通过
<script>
标签引入)时,如果没有使用async
或defer
属性,浏览器会立即下载并执行该JavaScript文件,期间会阻塞页面的渲染和响应,直到该文件执行完成。这会导致页面的加载和显示被延迟。
不阻塞页面的情况:
异步执行:通过使用异步执行的机制,如使用
async
和defer
属性,可以使JavaScript代码在下载过程中不阻塞页面的渲染和响应。异步执行的脚本会在后台下载,并在下载完成后才执行,这样页面的加载和显示可以继续进行。事件驱动执行:JavaScript常用于响应用户的交互事件,如点击、滚动、键盘输入等。这些事件触发时,浏览器会执行对应的JavaScript代码,但不会阻塞页面的渲染和响应。这样可以保持页面的流畅性和响应性。
为了避免JavaScript阻塞页面,可以采取以下优化策略:
- 将不需要立即执行的JavaScript代码使用
async
或defer
属性进行异步加载。 - 将JavaScript代码拆分成多个小模块,按需加载,减少单个文件的大小和执行时间。
- 避免执行耗时长的JavaScript操作,尽量优化代码逻辑和算法。
- 使用Web Workers进行后台计算,避免主线程的阻塞。
总之,JavaScript的执行方式和代码优化对页面的渲染和响应有重要影响。合理使用异步执行和优化代码,可以提高页面的加载速度和用户体验。
浏览器的垃圾回收机制
浏览器的垃圾回收(Garbage Collection,GC)机制是一种自动管理内存的机制,用于检测和释放不再被程序使用的内存资源,以避免内存泄漏和浪费。不同的浏览器和JavaScript引擎可能具有不同的垃圾回收策略,但一般包括以下主要的垃圾回收技术:
标记-清除(Mark and Sweep):这是最常用的垃圾回收算法之一。它的工作原理是通过标记不再被引用的对象,然后清除(释放)这些对象所占用的内存空间。垃圾回收器会从根对象开始遍历内存中的对象,标记所有与根对象相关联的对象,然后扫描整个堆(内存空间),将未被标记的对象视为垃圾并回收它们。
引用计数(Reference Counting):这种垃圾回收算法会为每个对象维护一个引用计数器,记录对象被引用的次数。当对象的引用计数为0时,表示没有任何代码引用该对象,因此可以被回收。然而,引用计数算法难以解决循环引用的问题,即两个或多个对象相互引用,但没有其他代码引用它们。现代的浏览器不再主要使用引用计数算法作为主要的垃圾回收策略。
分代回收(Generational Collection):这是一种基于对象存活时间的垃圾回收策略。根据观察,大部分对象在内存中存在的时间很短,而只有少数对象存在很长时间。基于这个观察,分代回收将内存分为不同的代(Generation),通常是新生代(Young Generation)和老年代(Old Generation)。新生代中的对象经常回收,而老年代中的对象则相对稳定。通过不同的回收策略和频率,提高垃圾回收的效率。
增量回收(Incremental Collection):为了减少垃圾回收造成的长时间停顿,一些浏览器引擎采用增量回收的技术。增量回收将垃圾回收的过程分解为多个小步骤,在执行这些步骤的过程中允许页面的其他操作继续进行。这样可以将垃圾回收的负载分散到较长的时间段,减少对页面响应的影响。
需要注意的是,具体的垃圾回收机制和算法可能会因浏览器和JavaScript引擎的不同而有所差异。现代的浏览器和JavaScript引擎通常会结合多种垃圾回收技术,并根据实际情况进行优化,以提供更好的性能和用户体验。
说一说浏览器的缓存机制?
浏览器的缓存机制是一种用于存储和重用网络资源的机制,以减少对服务器的请求和提高网页加载速度。当浏览器请求某个资源时,它会检查缓存是否已经包含了该资源的副本,如果有,那么就可以直接从缓存中获取资源,而不必再向服务器发起请求。
以下是浏览器缓存机制的一般工作流程:
请求资源:浏览器向服务器发起请求以获取特定的资源,例如HTML文档、CSS文件、JavaScript文件、图像等。
检查缓存:浏览器首先检查缓存,看是否已经有该资源的副本被存储在缓存中。
缓存命中:如果缓存中存在请求的资源副本,并且该副本仍然有效(未过期),浏览器会直接从缓存中获取资源,并不再向服务器发送请求。这称为缓存命中(Cache Hit)。
缓存未命中:如果缓存中不存在请求的资源副本,或者存在但已经过期,浏览器会向服务器发起请求,服务器返回最新的资源,并将其存储到缓存中,以备将来使用。这称为缓存未命中(Cache Miss)。
缓存控制:服务器可以通过响应头中的缓存控制指令(如Cache-Control和Expires)来控制资源在浏览器缓存中的行为,如缓存过期时间、缓存的验证等。
浏览器缓存机制包括以下几个关键概念:
强缓存:通过设置合适的响应头,如Cache-Control和Expires,服务器可以指示浏览器在一定时间内使用缓存副本。在缓存有效期内,浏览器直接从缓存中获取资源,无需再次请求服务器。
协商缓存:通过设置响应头中的Last-Modified和ETag,服务器可以进行协商缓存。浏览器会在后续请求中发送If-Modified-Since和If-None-Match头,服务器根据这些值判断资源是否已经改变。如果资源未改变,服务器返回304 Not Modified状态码,浏览器直接从缓存中获取资源。
缓存位置:浏览器可以将缓存的资源存储在不同的位置,包括内存缓存和硬盘缓存。内存缓存速度更快,但容量较小,适合存储频繁访问的资源;而硬盘缓存容量较大,适合存储较少访问的资源。
缓存刷新和失效:缓存资源可以通过强制刷新(Ctrl+F5)或清除浏览器缓存来手动刷新或失效。服务器端可以通过更改资源的URL或设置适当的缓存过期时间来使缓存失效。
通过合理设置缓存策略,可以减少对服务器的请求次数,提高网页加载速度,降低带宽消耗,从而提升用户体验和网站性能。但对于频繁更新的资源,需要注意及时更新缓存策略,以确保用户能够获取到最新的内容。
认识浏览器缓存
当浏览器请求一个网站时,会加载各种资源,对于一些不经常变动的资源,浏览器会将他们保存在本地内存中,下次访问时直接加载这些资源,提高访问速度。
如何知道资源是请求的服务器还是读取的缓存呢?
看上面这张图,有些资源的size值是大小,有些是from disk cache
,有些是from memory cache
,显示大小的是请求的服务器资源,而显示后面两种的则是读取的缓存。
- disk cache: 就是将资源存储在磁盘中,等待下次访问时不需重新下载,直接从磁盘中读取,它的直接操作对象为
CurlCacheManager
。(效率比内存缓存慢,但存储容量大,存储时间长) - memory cache: 就是将资源缓存到内存中,等待下次访问时不需重新下载,直接从内存中读取。(从效率上看它是最快的,从存活时间来看,它是最短的。)
- | memory cache | disk cache |
---|---|---|
相同点 | 只能存储一些派生类资源文件 | 只能存储一些派生类资源文件 |
不同点 | 退出进程时数据会被清除 | 退出进程时数据不会被清除 |
存储资源 | 一般脚本、字体、图片会存在内存当中 | 一般非脚本会存在内存当中,如css等 |
浏览器缓存分类
- 强缓存
- 协商缓存
浏览器在向服务器请求资源时,首先判断是否命中强缓存,没命中再判断是否命中协商缓存
强缓存
浏览器在加载资源时,会先根据本地缓存资源的header
中判断是否命中强缓存,如果命中则直接使用缓存中的资源,不会再向服务器发送请求。 (这里的header中的信息指的是 expires
和 cache-control
)
Expires
该字段是 http1.0 时的规范,它的值为一个绝对时间的 GMT 格式的时间字符串,比如 Expires:Mon,18 Oct 2066 23:59:59 GMT。这个时间代表着这个资源的失效时间,在此时间之前,即命中缓存。这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当服务器与客户端时间偏差较大时,就会导致缓存混乱。所以这种方式很快在后来的HTTP1.1版本中被抛弃了。
Cache-Control
Cache-Control 是 http1.1 时出现的 header 信息,主要是利用该字段的 max-age 值来进行判断,它是一个相对时间,例如 Cache-Control:max-age=3600
,代表着资源的有效期是 3600 秒。cache-control 除了该字段外,还有下面几个比较常用的设置值:
no-cache:需要进行协商缓存,发送请求到服务器确认是否使用缓存。
no-store:禁止使用缓存,每一次都要重新请求数据。
public:可以被所有的用户缓存,包括终端用户和 CDN 等中间代理服务器。
private:只能被终端用户的浏览器缓存,不允许 CDN 等中继缓存服务器对其缓存。
Cache-Control 与 Expires 可以在服务端配置同时启用,同时启用的时候 Cache-Control 优先级高。
协商缓存
当强缓存没命中时,浏览器会发送一个请求到服务器,服务器根据 header
中的信息来判断是否命中协商缓存。如果命中,则返回304 ,告诉浏览器资源未更新,可以使用本地缓存。 (这里的header信息指的是Last-Modify/If-Modify-Since
和 ETag/If-None-Match
)
Last-Modify/If-Modify-Since
浏览器第一次请求一个资源的时候,服务器返回的 header 中会加上 Last-Modify,Last-modify 是一个时间标识该资源的最后修改时间。
当浏览器再次请求该资源时,request 的请求头中会包含 If-Modify-Since,该值为缓存之前返回的 Last-Modify。服务器收到 If-Modify-Since 后,根据资源的最后修改时间判断是否命中缓存。
如果命中缓存,则返回 304,并且不会返回资源内容,并且不会返回 Last-Modify。
缺点:
短时间内资源发生了改变,Last-Modified 并不会发生变化。
周期性变化。如果这个资源在一个周期内修改回原来的样子了,我们认为是可以使用缓存的,但是 Last-Modified 可不这样认为,因此便有了 ETag。
ETag/If-None-Match
与 Last-Modify/If-Modify-Since 不同的是,Etag/If-None-Match 返回的是一个校验码。ETag 可以保证每一个资源是唯一的,资源变化都会导致 ETag 变化。服务器根据浏览器上送的 If-None-Match 值来判断是否命中缓存。
与 Last-Modified 不一样的是,当服务器返回 304 Not Modified 的响应时,由于 ETag 重新生成过,response header 中还会把这个 ETag 返回,即使这个 ETag 跟之前的没有变化。
Last-Modified 与 ETag 是可以一起使用的,服务器会优先验证 ETag,一致的情况下,才会继续比对 Last-Modified,最后才决定是否返回 304。
总结
当浏览器访问一个已经访问过的资源是,它的步骤是:
1.先看是否命中强缓存,命中🎯的话直接使用缓存
2.没命中强缓存,则会发送请求到服务器看是否命中🎯协商缓存
3.如果命中了协商缓存,服务器会返回304告诉浏览器可以使用本地缓存
4.没命中协商缓存,则服务器会返回新的资源给浏览器
什么是浏览器的同源策略,以及跨域?
浏览器的同源策略(Same-Origin Policy)是一种安全机制,用于限制不同源(Origin)之间的交互,以防止恶意网站获取或篡改用户的敏感数据。同源指的是协议(Protocol)、域名(Domain)和端口(Port)三者完全相同。
同源策略规定,来自同一源的文档或脚本可以自由地交互,包括读取和修改彼此的数据;而来自不同源的文档或脚本则受到限制,无法直接访问对方的数据或执行对方的操作。
同源策略主要限制以下几个方面的行为:
DOM访问限制:脚本只能访问和操作与其所属页面具有相同源的文档对象模型(DOM)。跨源访问DOM会受到阻止,例如通过JavaScript获取跨域页面的子窗口或iframe的内容。
网络请求限制:XMLHttpRequest和Fetch等网络请求方式受到同源策略的限制。脚本只能向同源的URL发起请求,跨域请求会被浏览器拦截。
Cookie限制:浏览器会按照同源策略限制Cookie的读取和发送。跨域请求默认不会发送相应域名的Cookie,除非服务器明确指定允许。
跨域资源共享(CORS):为了实现跨域请求,服务器可以设置响应头中的Access-Control-Allow-Origin字段,指定允许访问资源的域名。
跨域(Cross-Origin)指的是在浏览器中从一个源(Origin)获取资源或与一个源进行交互时,涉及到不同的域名、协议或端口。跨域是由同源策略所限制的,如果违反了同源策略,浏览器会阻止跨域请求或访问。
要实现跨域访问,可以通过以下方法:
JSONP:利用script标签的src属性没有跨域限制的特点,通过动态插入script标签来加载跨域的JavaScript文件,并利用回调函数的方式进行数据传递。
CORS:服务器通过设置响应头中的Access-Control-Allow-Origin字段,允许特定的域名访问资源。浏览器在收到响应时会检查该字段,如果允许则将响应返回给页面。
代理服务器:通过在同一域名下设置代理服务器,将跨域请求转发到目标服务器并返回结果,从而避免了浏览器的同源策略限制。
需要注意的是,跨域访问是一种潜在的安全风险,应谨慎使用,并确保在允许跨域访问时进行适当的安全验证和防护措施,以防止恶意利用和数据泄露。
说说什么是XSS攻击
XSS(Cross-Site Scripting)攻击是一种常见的网络安全漏洞,它允许攻击者将恶意脚本注入到受信任的网页中,使其在用户的浏览器上执行。这种攻击利用了网站对用户输入的不足过滤和验证,导致用户在浏览网页时执行了攻击者的恶意脚本。
XSS攻击通常分为以下三种类型:
存储型XSS:攻击者将恶意脚本存储到目标网站的数据库中,当其他用户浏览包含该恶意脚本的页面时,恶意脚本会被执行。这种攻击常见于用户留言板、评论区等允许用户提交内容的地方。
反射型XSS:攻击者构造恶意URL,将包含恶意脚本的参数传递给目标网站。当用户点击包含恶意URL的链接时,目标网站会将恶意脚本作为响应返回给用户的浏览器,浏览器执行该脚本。这种攻击常见于通过URL传递参数的搜索功能、跳转链接等。
DOM型XSS:攻击者通过修改目标网页的DOM结构,将恶意脚本注入到页面中,并在用户浏览器中执行。与存储型和反射型XSS不同,DOM型XSS攻击不涉及服务器的响应,而是直接操作浏览器中的DOM结构。
XSS攻击的危害包括但不限于以下几点:
盗取用户信息:恶意脚本可以窃取用户的敏感信息,如登录凭证、Cookie、个人资料等。
劫持用户会话:攻击者可以利用XSS攻击获取用户的会话信息,并冒充用户执行恶意操作。
传播恶意代码:攻击者可以通过XSS攻击在受影响的网站上注入恶意代码,进一步攻击其他用户或传播恶意软件。
为了防止XSS攻击,开发者可以采取以下措施:
输入验证和过滤:对用户输入的数据进行验证和过滤,确保只接受合法和预期的输入。例如,可以使用白名单过滤机制,限制输入中的特殊字符和标签。
输出编码:在将用户输入或其他动态内容插入到网页中时,确保进行适当的编码,以防止恶意脚本被执行。常见的编码方式包括HTML实体编码、URL编码等。
设置HTTP头部:通过设置Content Security Policy(CSP)和X-XSS-Protection等HTTP头部,可以进一步增强浏览器的安全防护能力。
教育用户:提高用户的安全意识,教育他们不要点击可疑的链接、不信任的网站或提供个人信息的表单。
综上所述,对于开发者和用户来说,了解XSS攻击的原理和防范措施非常重要,以保护网站和用户的安全。
说说什么是CSRF攻击?
CSRF(Cross-Site Request Forgery)攻击是一种利用受信任用户的身份执行未经授权的操作的攻击方式。攻击者通过诱导用户访问恶意网页或点击恶意链接,在用户的浏览器中执行恶意代码,使其在用户不知情的情况下发送请求到目标网站,以执行攻击者所期望的操作。
CSRF攻击的过程通常包括以下步骤:
攻击者构造恶意请求:攻击者创建一个恶意网页或链接,并在其中包含对目标网站的请求,例如修改账户信息、发起转账请求等。
用户被诱导执行恶意请求:攻击者通过各种手段诱导用户访问恶意网页或点击恶意链接,使恶意请求在用户的浏览器中被执行。这可能包括通过电子邮件、社交媒体、论坛等方式进行诱导。
用户浏览器发送恶意请求:用户的浏览器在访问恶意网页或点击恶意链接后,会自动发送包含攻击者构造的恶意请求的HTTP请求到目标网站。
目标网站执行恶意请求:目标网站接收到恶意请求后,由于请求中包含了用户的身份验证信息(如Cookie),将误认为该请求是合法的,并按照请求的指令执行相应的操作,导致攻击成功。
CSRF攻击的危害包括但不限于以下几点:
账户操作篡改:攻击者可以以受信任用户的身份执行未经授权的操作,如修改账户密码、更改用户设置等。
资金转移和盗窃:攻击者可以通过CSRF攻击发起转账请求、购买商品等操作,导致用户的资金被盗或损失。
为了防范CSRF攻击,开发者可以采取以下措施:
使用随机令牌:在每个请求中包含一个随机生成的令牌(CSRF Token),并验证该令牌的有效性。攻击者无法获得正确的CSRF令牌,从而无法构造有效的恶意请求。
检测Referer头:服务器端可以检查请求头中的Referer字段,确保请求来自于同一站点。然而,该方法依赖于浏览器发送正确的Referer头,因此并非完全可靠。
使用同源检测:在关键操作中,服务器可以检查请求的来源是否与目标网站具有相同的源(Origin),如果不同则拒绝请求。
限制敏感操作的访问权限:对于一些敏感操作,可以要求用户进行额外的身份验证,如输入密码、使用二次验证等。
教育用户:提高用户的安全意识,教育他们不要点击可疑的链接、不信任的网站,以及定期清除浏览器缓存和Cookie等。
综上所述,了解CSRF攻击的原理和防范措施对于开发者和用户来说都至关重要,以保护网站和用户的安全。
浏览器缓存读取规则
可以分成 Service Worker、Memory Cache、Disk Cache 和 Push Cache,那请求的时候 from memory cache 和 from disk cache 的依据是什么,哪些数据什么时候存放在 Memory Cache 和 Disk Cache中?
浏览器缓存的读取规则是根据缓存存储的位置和缓存策略来确定的。以下是有关Memory Cache和Disk Cache的一般规则:
Memory Cache(内存缓存):
- 作用:Memory Cache是浏览器中的内存缓存,用于临时存储最近使用的资源,以提供快速访问。
- 存放内容:通常会缓存已经访问过的资源,如HTML文档、CSS样式表、JavaScript脚本、图片等。
- 存放时间:数据在页面会话期间保持有效,当页面关闭或刷新时,Memory Cache中的数据将被清除。
Disk Cache(磁盘缓存):
- 作用:Disk Cache是浏览器中的磁盘缓存,用于持久存储资源,以便在后续访问时能够快速加载。
- 存放内容:通常会缓存经常访问的资源,如CSS、JavaScript、图片、字体文件等。
- 存放时间:数据可以在多个页面会话之间保持有效,即使浏览器关闭,下次打开相同的页面时,可以从磁盘缓存中加载数据。
请求从Memory Cache和Disk Cache中读取的依据主要是URL和缓存策略:
- 当浏览器收到一个请求时,它会检查该请求对应的URL是否存在于Memory Cache中。如果存在且未过期(根据缓存策略),则会直接从Memory Cache中读取数据,并不会发送网络请求。
- 如果URL不在Memory Cache中或已过期,则浏览器会检查Disk Cache中是否存在该URL的缓存。如果存在且未过期,则会从Disk Cache中读取数据,并不会发送网络请求。
- 如果URL既不在Memory Cache中也不在Disk Cache中,浏览器会发送网络请求获取数据,并将接收到的响应数据存储到Memory Cache和Disk Cache中,以便后续使用。
需要注意的是,具体的缓存行为和策略可以由服务器通过HTTP响应头中的Cache-Control、Expires等字段进行配置,这些字段指定了资源在客户端缓存中的存储时间和行为。浏览器会根据这些响应头来判断是否使用缓存以及缓存的存储位置。
浏览器的缓存机制 强制缓存 && 协商缓存
浏览器的缓存机制主要包括强制缓存和协商缓存两种方式,它们可以有效地减少对服务器的请求,提高页面加载速度和用户体验。
1. 强制缓存: 强制缓存是通过设置缓存响应头来告知浏览器在一段时间内直接使用本地缓存,而不发送请求到服务器。
强制缓存的过程如下:
- 当浏览器首次请求某个资源时,服务器返回该资源的响应,并在响应头中设置缓存相关的字段,如
Cache-Control
或Expires
。 - 浏览器将该资源及其缓存相关信息存储在本地缓存中。
- 下次请求该资源时,浏览器会检查缓存相关信息,如果缓存未过期(根据响应头中的缓存控制字段判断),浏览器直接从缓存中获取资源,不发送请求到服务器。
常见的缓存控制字段包括:
Cache-Control
: 指定缓存控制策略,如max-age
(缓存有效时间)、no-cache
(不直接使用缓存,需要进行协商缓存)等。Expires
: 指定资源的过期时间,是一个绝对时间。
2. 协商缓存: 协商缓存是在强制缓存失效后,浏览器与服务器进行通信,通过协商判断是否需要重新获取资源。
协商缓存的过程如下:
- 当浏览器发起请求并命中强制缓存但缓存已过期时,浏览器发送请求到服务器,并在请求头中包含缓存相关的字段,如
If-Modified-Since
和If-None-Match
。 - 服务器收到请求后,根据请求头中的字段与服务器上的资源进行比较。
- 如果资源未发生变化,服务器返回 HTTP 304 Not Modified 响应,响应中不包含实际的资源,只包含一些缓存相关的响应头。
- 如果资源发生变化,服务器返回新的资源以及相应的缓存相关信息。
- 浏览器接收到响应后,根据服务器的响应进行处理:
- 如果收到 HTTP 304 响应,浏览器直接从缓存中获取资源。
- 如果收到新的资源,浏览器将新的资源存储在缓存中,并更新缓存相关信息。
常见的协商缓存字段包括:
If-Modified-Since
:指定资源上次的修改时间,服务器根据该字段判断资源是否发生变化。If-None-Match
:指定资源的唯一标识(通常是 ETag),服务器根据该字段判断资源是否发生变化。
通过强制缓存和协商缓存的机制,浏览器可以根据资源的缓存策略决定是否发送请求到服务器,从而提高页面加载速度和网络资源利用效率。
了解v8引擎吗,一段js代码如何执行的
在执行一段代码时,JS 引擎会首先创建一个执行栈 然后JS引擎会创建一个全局执行上下文,并push到执行栈中, 这个过程JS引擎会为这段代码中所有变量分配内存并赋一个初始值(undefined),在创建完成后,JS引擎会进入执行阶段,这个过程JS引擎会逐行的执行代码,即为之前分配好内存的变量逐个赋值(真实值)。 如果这段代码中存在function的声明和调用,那么JS引擎会创建一个函数执行上下文,并push到执行栈中,其创建和执行过程跟全局执行上下文一样。但有特殊情况,即当函数中存在对其它函数的调用时,JS引擎会在父函数执行的过程中,将子函数的全局执行上下文push到执行栈,这也是为什么子函数能够访问到父函数内所声明的变量。 还有一种特殊情况是,在子函数执行的过程中,父函数已经return了,这种情况下,JS引擎会将父函数的上下文从执行栈中移除,与此同时,JS引擎会为还在执行的子函数上下文创建一个闭包,这个闭包里保存了父函数内声明的变量及其赋值,子函数仍然能够在其上下文中访问并使用这边变量/常量。当子函数执行完毕,JS引擎才会将子函数的上下文及闭包一并从执行栈中移除。 最后,JS引擎是单线程的,那么它是如何处理高并发的呢?即当代码中存在异步调用时JS是如何执行的。比如setTimeout或fetch请求都是non-blocking的,当异步调用代码触发时,JS引擎会将需要异步执行的代码移出调用栈,直到等待到返回结果,JS引擎会立即将与之对应的回调函数push进任务队列中等待被调用,当调用(执行)栈中已经没有需要被执行的代码时,JS引擎会立刻将任务队列中的回调函数逐个push进调用栈并执行。这个过程我们也称之为事件循环。 附言:需要更深入的了解JS引擎,必须理解几个概念,执行上下文,闭包,作用域,作用域链,以及事件循环。建议去网上多看看相关文章,这里推荐一篇非常精彩的博客,对于JS引擎的执行做了图形化的说明,更加便于理解。
什么是沙箱?浏览器的沙箱有什么作用?
沙箱(Sandbox)是一种安全机制,用于限制代码或应用程序的执行环境,以防止其对系统或其他资源造成不受控制的访问或损害。在计算机科学中,沙箱是一种隔离的环境,其中可以执行受限制的代码,而不会对其周围的环境产生负面影响。
在浏览器中,沙箱是一种安全机制,旨在隔离和限制网页中的代码执行。浏览器沙箱的主要作用如下:
安全隔离: 浏览器沙箱通过创建一个受限制的执行环境,将网页中的代码与底层操作系统和其他网页内容隔离开来。这样,恶意代码或错误的代码执行将受到限制,不会对浏览器和用户的设备产生不良影响。
资源限制: 浏览器沙箱可以限制代码对系统资源的访问,例如文件系统、网络连接、摄像头、麦克风等。这样可以防止恶意代码滥用这些资源,保护用户的隐私和设备的安全。
代码执行控制: 浏览器沙箱可以对代码的执行行为进行控制和监控,例如限制脚本执行时间、禁止特定的 API 调用、限制跨域请求等。这样可以确保网页中的代码在安全的范围内运行,并提高浏览器的稳定性和安全性。
插件和广告的限制: 浏览器沙箱可以应用于插件和广告等第三方内容,以防止它们对浏览器和用户环境的潜在威胁。通过将插件和广告代码运行在受限的沙箱中,可以减少其对系统的访问权限,提高整体安全性。
浏览器沙箱通常由浏览器厂商实现,并作为浏览器的一部分来提供安全保护。不同的浏览器可能会有不同的沙箱实现和策略,但它们的目标都是提供一种安全的执行环境,以保护用户和系统免受恶意代码的侵害。
打开 Chrome 浏览器一个 Tab 页面,至少会出现几个进程?
最新的 Chrome 浏览器包括至少四个: 1 个浏览器(Browser)主进程、1 个 GPU 进程、1 个网络(NetWork)进程、多个渲染进程和多个插件进程, 当然还有复杂的情况;
页面中有 iframe 的话, iframe 会单独在进程中
有插件的话,插件也会开启进程
多个页面属于同一站点,并且从 a 打开 b 页面,会共用一个渲染进程
装了扩展的话,扩展也会占用进程
这些进程都可以通过 Chrome 任务管理器来查看
即使如今多进程架构,还是会碰到单页面卡死的最终崩溃导致所有页面崩溃的情况,讲一讲你的理解?
提供一种情况,就是同一站点, 围绕这个展开也行。
Chrome 的默认策略是,每个标签对应一个渲染进程。但是如果从一个页面打开了新页面,而新页面和当前页面属于同一站点时,那么新页面会复用父页面的渲染进程。官方把这个默认策略叫 process-per-site-instance。
更加简单的来说,就是如果多个页面符合同一站点,这几个页面会分配到一个渲染进程中去, 所以有这样子的一种情况, 一个页面崩溃了,会导致同一个站点的其他页面也奔溃,这是因为它们使用的是同一个渲染进程。
有人会问为什么会跑到一个进程里面呢?
你想一想呀, 属于同一家的站点,比如下面三个:
https://time.geekbang.org https://www.geekbang.org https://www.geekbang.org:8080 它们在一个渲染进程中的话,它们就会共享 JS 执行环境,也就是 A 页面可以直接在 B 页面中执行脚本了, 有些时候就是有这样子的需求嘛。