[前端面试]浏览器

sessionstorage 与localStorage之间的区别

sessionStorage和localStorage都是浏览器客户端存储数据的方式。

它们允许网站在用户的浏览器中存储键值对,

并且这些数据在页面重新加载后仍然可用。

会话是什么

会话(Session)是指在指定的时间段内,用户在浏览器(或APP、小程序等客户端)上与网站进行的一系列交互行为的集合

。简而言之,当用户打开一个浏览器窗口,开始访问某个网站,并在一段时间内与网站进行交互(如点击链接、填写表单等),直到用户关闭浏览器窗口或会话超时,整个过程就被视为一个会话。

区别

  1. 生命周期
    • sessionStorage:生命周期与当前会话一致,一旦会话结束关闭,不再存在。
    • localStorage:其生命周期是永久的,除非用户手动删除数据或浏览器清理了存储。
  2. 存储大小
    • sessionStorage和localStorage的存储大小限制通常是相同的,大多数现代浏览器都提供了大约5MB的存储空间。
  3. 数据共享
    • sessionStorage的数据只能在当前会话的页面之间共享,且仅限于同源(相同的协议、域名和端口)的页面。
    • localStorage的数据可以在所有同源页面之间共享,无论它们是否属于同一个会话。
  4. 数据格式
    • sessionStorage和localStorage都只能存储字符串类型的数据。如果需要存储复杂对象,可以使用JSON.stringify()方法将对象转换为json字符串,然后在需要时使用JSON.parse()方法将其还原为对象。
  5. 访问方式
    • 可以通过window.sessionStorage和window.localStorage来访问这两个存储对象。它们提供了setItem()、getItem()、removeItem()、clear()等方法来操作存储的数据。
  6. 使用场景
    • sessionStorage适用于存储只需要在当前会话期间保持有效的数据,例如用户的临时登录信息、表单的临时数据等。
    • localStorage适用于存储需要长期保持的数据,例如用户的偏好设置、缓存的数据等。

注意事项

  • 在使用sessionStorage和localStorage时,需要注意浏览器的兼容性问题。虽然现代浏览器大多支持这两个存储对象,但在一些旧版本的浏览器上可能存在兼容性问题。
  • 在存储敏感数据时,需要注意安全性问题。虽然这两个存储对象都提供了在客户端存储数据的功能,但它们并不提供加密或身份验证等安全机制。因此,在存储敏感数据时,需要采取额外的安全措施来保护数据的安全性。

http 无状态

HTTP是一个无状态协议,每个HTTP请求都是独立的,服务器不会保存与先前请求相关的信息。

它指的是服务器在处理客户端的请求时,不会将请求和先前状态相关联。

但是在需要客户端与服务器进行动态交互的Web应用程序中,服务器需要记住上一次请求的信息。例如,在购物车功能中,服务器需要知道用户在商品浏览页面添加的商品信息,以便在购物车页面中显示。由于HTTP是无状态的,服务器无法直接获取这些信息。

1)Cookie:

Cookie 是存储在用户浏览器端的一个小型数据文件,用于跟踪和保存用户的状态信息。

主要用于保持用户登录状态、跟踪用户行为、存储用户偏好等。

存储在浏览器端

2)Session:

Session 是服务器端保存用户状态的机制,每个用户会话都有一个唯一的 Session ID。

主要用于跟踪用户在服务器上的状态信息,例如登录状态和购物车内容。

存储在服务器端,然后对应的 Session ID 通过 Cookie 保存在客户端浏览器中。

3)Token:

Token 本质是一种加密的字符串,用于身份验证和授权,可以包含用户信息和权限,用于验证用户身份或授权访问资源。

认证后,后端服务会返回 Token,存储在客户端(浏览器或移动应用中),后续客户端访问服务端需要带上这个 Token。

它们之间使用场景区别:

  • Cookie:主要用于客户端状态的简单存储和追踪。
  • Session:用于服务器端的复杂状态管理,特别是在需要存储大量会话数据时。
  • Token:用于无状态的认证和授权,特别是在分布式和跨域环境下。

简单来说,Cookie 和Session 更适合用于单次会话的认证和状态管理,而 Token 更适合用于跨会话的认证和状态管理。

什么是xss攻击,如何防范

XSS攻击,即跨站脚本攻击(Cross Site Scripting),是一种代码注入攻击。攻击者通过在网站注入恶意脚本,使之在用户的浏览器上运行,从而盗取用户的信息如cookie等。

XSS的本质是因为网站没有对恶意代码进行过滤,与正常的代码混合在一起了,浏览器没有办法分辨哪些脚本是可信的,从而导致了恶意代码的执行。

XSS 攻击,全称是跨站脚本攻击(Cross-Site Scripting),是一种代码注入攻击方式。攻击者通过在网页中注入恶意的脚本(通常是 JavaScript 代码),当用户浏览该网页时,恶意脚本就会在用户的浏览器中执行,从而达到劫持用户会话、伪造用户输入、窃取用户信息等目的。

防范 XSS 攻击的主要方法可以归纳为以下几点: 1)输入验证:对用户提交的信息进行严格的合法性检查,过滤或清理可能包含的恶意代码。 2)输出编码:对输出内容进行适当的编码,确保即便含有恶意代码也不会被执行。 3)使用安全库:使用诸如 Content Security Policy (CSP) 等浏览器提供的安全机制。 4)避免使用危险的 HTML 标签或属性,如 <script><iframe>onerror 事件处理程序等。

什么是csrf攻击,如何防范

CSRF(Cross-Site Request Forgery)攻击,即跨站请求伪造,这种攻击利用用户在已登录网站上的身份验证信息,在用户不知情的情况下,冒充用户向服务器发送恶意请求,从而执行未经用户授权的操作。

CSRF攻击的原理

CSRF攻击通常发生在用户已经登录了某个网站的情况下。攻击者会在自己的网站上构造一个恶意链接或表单,诱导用户点击该链接或提交表单。由于用户已经登录了目标网站,并且浏览器会自动携带用户的身份信息(如Cookie、Session等),因此恶意请求会携带用户的身份信息发送到目标网站。目标网站无法区分是用户自己发起的请求还是攻击者伪造的请求,因此容易受到攻击。

防范措施

为了防范CSRF攻击,可以采取以下措施:

  1. 使用CSRF令牌(Token)
    • 在每个用户请求中生成唯一的CSRF令牌,并将其嵌入到表单或URL中。
    • 服务器在接收到请求时验证令牌的合法性,只有包含正确令牌的请求才被认为是合法的。
  2. 检查Referer字段
    • 服务器可以通过检查HTTP请求头中的Referer字段来验证请求的来源是否合法。
    • 但需要注意,Referer字段可能会被更改或伪造,因此这种方法并非完全可靠,通常作为辅助手段使用。
  3. 设置SameSite属性
    • 通过为Cookie设置SameSite属性为Strict或Lax,可以限制Cookie的发送,阻止跨站点请求。
    • Strict模式下,Cookie仅在同源请求中发送;Lax模式下,Cookie在部分跨站请求(如GET请求)中不发送,但在表单提交等操作时仍会发送。
  4. 双重提交Cookie
    • 在每个请求中,同时通过Cookie和请求参数提交一个相同的token。
    • 服务器端验证两者是否一致,以确保请求的有效性。
  5. 用户教育和安全意识
    • 用户应该时刻保持警惕,不点击不信任的链接,尤其是来自未知或可疑来源的链接。
    • 定期更新操作系统和浏览器,并使用安全可靠的防病毒软件。
  6. 定期更新和维护网站
    • 开发人员和管理员应定期更新和维护网站,修补已知的漏洞,并及时应用安全补丁。
  7. 启用CSRF保护
    • 在使用Spring Security等安全框架时,可以启用CSRF保护功能,自动为请求添加和验证CSRF令牌。

什么是回流与重绘

回流(Reflow)

回流是指浏览器重新计算元素的布局,位置和大小的过程。

常发生在以下过程:

  1. 添加或删除可见的 DOM 元素。
  2. 元素尺寸发生变化,如宽度、高度、边距、填充等。
  3. 页面布局发生变化,如改变窗口大小。
  4. CSS 伪类激活,如:hover。
  5. 计算 offsetWidth、offsetHeight 等属性。

重绘(Repaint)

重绘是浏览器在元素的外观发生变化,但不影响布局时所发生的过程。

重绘通常发生在场景:

  • 改变元素的颜色、背景、边框等样式,但不影响元素尺寸和位置。

回流与重绘的关系

  1. 触发条件:回流通常是在DOM结构或元素布局发生变化时触发,而重绘则是在元素样式属性发生变化时触发。
  2. 性能开销:由于回流需要重新计算元素的位置和大小,所以性能开销较大。而重绘只是重新绘制元素的外观,开销相对较小。
  3. 必然联系:回流必然伴随着重绘。当元素的位置和大小发生改变时,不仅需要进行回流计算,还需要进行重绘操作。但重绘不一定会引起回流。

减少回流和重绘的方法:

  1. 避免频繁操作样式:多次修改样式时,可以使用一个 class 来修改,或者通过修改 style 属性进行批量操作。
  2. 避免逐项改变样式:使用 CSS 的 transform、opacity 等属性进行动画,而不是改变宽度、高度、位置等会触发回流的属性。
  3. 使用文档片段(DocumentFragment)或者 offscreen 元素进行批量操作:在对 DOM 元素进行大量操作时,可以先将它们从文档流中移除,然后在内存中进行操作,最后再插入文档流中。
  4. 避免使用 table 布局:table 布局中的元素发生回流时,会影响到整个表格,从而导致更多的回流。
  5. 对具有复杂动画的元素使用绝对定位:将动画元素脱离文档流,减少回流对其他元素的影响。
  6. 避免频繁访问布局信息:如 offsetWidth、offsetHeight 等,可以在访问前将这些值缓存起来,避免多次触发回流。

什么是浏览器的同源策略

浏览器的同源策略(Same-Origin Policy)是一种安全策略,

它规定了浏览器只允许当前网页的脚本与来自同一站点(协议、主机、端口号相同)的窗口进行交互,而限制了与不同源(协议、主机、端口号任一不同)的窗口进行交互。这种限制能够有效保障用户的信息安全和隐私。

然而,有时需要在不同源之间进行数据交换,为此引入了一些跨域解决方案,如跨域资源共享(CORS)和跨文档消息传递(PostMessage)等。这些解决方案允许在特定条件下进行跨域交互,同时保持了一定的安全性。

如何解决跨域问题

跨域问题 (Cross-Origin Resource Sharing,CORS)是由于浏览器的同源策略 (Same-Origin Policy)导致的。同源策略指的是,如果两个 URL 的协议、主机名和端口号都相同,那么它们就是同源的,否则就是跨域的 。当网页发起跨域请求时,浏览器会根据同源策略限制请求。解决跨域问题的方法有以下

1. CORS(跨域资源共享)

CORS 是一种通过添加一些 HTTP 头 来允许浏览器跨域访问资源 的机制,主要是服务端配置。服务端需要在响应头中添加 Access-Control-Allow-Origin 和其他一些参数,指示允许哪些域名进行跨域请求

  • 优点:实现简单,只需要服务器端配置响应头。
  • 缺点:需要服务器端的支持和配置。

在 Spring Boot 项目中,可以通过以下方式实现 CORS:

  • 使用 @CrossOrigin 注解在方法或类上。
  • 通过配置文件实现全局跨域。
  • 通过 CorsFilter 对象实现全局跨域。

2. JSONP(JSON with Padding)

JSONP 是一种利用 <script> 标签的跨域请求方式。它通过动态创建一个 <script> 标签,并将跨域请求的 URL 作为其 src 属性。服务器端需要将响应的数据以函数调用的形式返回,客户端通过定义对应的回调函数来接收数据。

实现原理是在服务端生成一个 JavaScript 函数,客户端使用 < script > 标签请求该函数,服务端返回该函数的调用,并将需要传输的数据作为函数参数传入。

  • 优点:兼容性好,可以解决主流浏览器的跨域问题。
  • 缺点:仅支持 GET 请求,不安全,可能遭受 XSS 攻击。

3. 代理服务器

可以通过搭建一个代理服务器(如 Node.js、Nginx)来转发跨域请求。

客户端将跨域请求发送到代理服务器,代理服务器再将请求转发到目标服务器,目标服务器返回的数据经过代理服务器后再返回给客户端。

  • 优点:可以解决跨域问题,同时可以对请求和响应进行更多的控制和定制。
  • 缺点:需要额外的开发和维护工作。

4. WebSocket

WebSocket 是一种基于 TCP 的全双工通信协议,它允许客户端和服务器之间建立持久的连接,并进行实时的双向数据传输。通过 WebSocket,跨域通信可以更加高效和实时。

  • 优点:适用于需要实时通信的场景,如实时聊天、实时数据推送等。
  • 缺点:需要客户端和服务器都支持 WebSocket 协议。

浏览器渲染过程

  1. DNS查询,解析域名
    • 当用户在浏览器中输入一个网址时,浏览器首先会进行DNS查询,将域名解析为对应的IP地址。
  2. 建立TCP连接
    • 浏览器与服务器之间需要建立TCP连接,以便进行数据传输。
  3. 发出HTTP请求
    • 浏览器通过HTTP协议向服务器发送请求,请求获取网页资源。
  4. 等待服务器响应
    • 服务器接收到请求后,会处理请求并返回相应的资源,如HTML、CSS、JavaScript、图片等。
  5. 浏览器接收并解析资源
    • 浏览器接收到服务器返回的资源后,会开始解析这些资源。
      • 解析HTML:浏览器会解析HTML文档,构建DOM树(文档对象模型)。DOM树是HTML文档在内存中的表示形式,它包含了文档中的所有元素和它们的层次关系。
      • 解析CSS:同时,浏览器会解析CSS样式表,构建CSSOM树(CSS对象模型)。CSSOM树表示了文档中所有元素的样式信息。
      • 解析JavaScript:如果HTML文档中包含了JavaScript代码,浏览器会解析并执行这些代码。JavaScript代码可能会修改DOM树或CSSOM树。
  6. 构建渲染树
    • 在构建完DOM树和CSSOM树之后,浏览器会结合这两个树来构建渲染树。渲染树只包含可见元素和它们的样式信息。
  7. 布局(Layout)
    • 浏览器会根据渲染树计算每个元素的几何信息(如位置、大小等),这个过程称为布局或回流。
  8. 绘制(Painting)
    • 最后,浏览器会将渲染树的每个节点绘制到屏幕上。这个过程称为绘制或重绘。

script中的defer 和 async的区别

控制脚本异步加载的属性,执行时机不同,defer会在html文件加载完成之后执行,async则会在加载完成之后立即执行不管html是否还在加载中

defer属性

  • 加载方式 :使用defer属性的脚本会在HTML解析的同时异步加载。
  • 执行顺序 :所有带有defer属性的脚本会按照它们在页面中的出现顺序依次执行。
  • 执行时机 :脚本会在HTML文档解析完毕后执行,也就是在DOMContentLoaded事件触发之前执行,但不会阻塞页面的解析。
  • 适用场景 :当脚本依赖于DOM结构时,使用defer是理想的,因为它保证了脚本执行时DOM已经完全加载完成。

async属性

  • 加载方式 :使用async属性的脚本也会异步加载,与HTML解析同时进行。
  • 执行顺序 :脚本会在加载完成后立即执行,不保证按照它们在页面中的出现顺序执行。
  • 执行时机:一旦脚本加载完成,就会立即执行,可能会在HTML解析完成之前执行,也可能在解析过程中执行。
  • 适用场景:用于独立、不依赖于其他脚本或DOM内容的脚本,例如分析工具或广告脚本,因为它们可以尽快执行而不影响页面的解析。

总结

  • 加载顺序async无序(哪个脚本先加载完哪个先执行),defer有序(按照HTML中的顺序执行)。
  • 执行时机async脚本一旦加载完成立刻执行,defer脚本会在HTML解析完成之后执行。
  • 使用建议
    • 当脚本依赖于页面的DOM结构时,使用defer更安全。
    • 当脚本与其他脚本和页面结构无关时,可以使用async以加快加载和执行速度。

v8引擎的垃圾回收机制如何工作

V8引擎简介

V8是一种开源的JavaScript引擎,它主要用于Chrome浏览器和Node.js环境。V8引擎中的垃圾回收机制负责自动管理内存的分配和释放,以确保程序运行期间不会出现内存泄漏或垃圾堆积的问题。

垃圾回收机制原理

V8引擎的垃圾回收机制基于代际假说和分代回收的原理。代际假说认为,大部分对象在内存中存在的时间很短,而少数对象会存活较长时间。因此,V8将内存分为新生代(young generation)和老生代(old generation)两个区域。

  1. 新生代(Young Generation)
    • 用于存放新创建的对象。
    • 空间相对较小,因为大部分对象很快就会被回收。
    • 使用Scavenge算法进行垃圾回收。该算法将新生代内存空间分为From空间和To空间。新创建的对象首先被分配到From空间,当From空间满时,会触发垃圾回收过程。回收过程中,V8首先进行标记操作,标记活跃的对象,然后将这些对象复制到To空间,同时进行压缩等操作。最后,From空间和To空间的角色互换,完成垃圾回收。
  2. 老生代(Old Generation)
    • 用于存放经过一定时间仍然存活的对象。
    • 空间相对较大,因为老生代中的对象存活时间较长。
    • 使用标记-清除(Mark-Sweep)和标记-压缩(Mark-Compact)两种算法进行垃圾回收。标记-清除算法首先进行标记操作,标记出活跃的对象,然后清除未标记的对象。标记-压缩算法在清除未标记的对象后,将存活的对象压缩到内存的一端,从而减少内存碎片化。

增量标记与并行回收

  • 增量标记:为了避免长期停顿,V8 会在标记阶段使用增量标记来将工作切成更小的块。
  • 并发回收:在清除阶段,V8 支持并发回收,使得垃圾回收工作可以在多个线程上并行进行,从而减少主线程停顿时间。

垃圾回收过程

  1. 标记阶段:遍历所有对象,将可达的活动对象进行标记。
  2. 清理阶段:统一清理内存中被标记为可回收的对象。
  3. 内存整理阶段:当清理完内容后,会存在大量不连续的空间,因此需要重新整理内存,使存活的对象在内存地址上变得连续。

对象晋升

在新生代中,当一个对象经过多次复制仍然存活时,或者当To空间的内存占用比超过限制时(如25%),该对象会被晋升到老生代。老生代中的对象由于存活时间较长,垃圾回收的成本较高,因此使用更高效的算法进行处理。

进程与线程的区别

  1. 资源分配 :进程是资源分配的基本单位,每个进程都有独立的地址空间和资源;而线程是CPU调度的基本单位,线程共享进程的地址空间和资源。
  2. 独立性:进程之间是相互独立的,一个进程的崩溃不会影响其他进程;而线程是进程的一部分,一个线程的崩溃会导致整个进程的崩溃(在保护模式下,其他线程可能会受到影响,但整个进程通常会被终止)。
  3. 开销:进程切换需要较大的开销,因为需要保存和恢复上下文信息等;而线程切换开销相对较小,因为线程共享进程的地址空间和资源。
  4. 通信:进程间通信需要通过特定的机制,如管道、消息队列等;而线程之间可以直接通过共享内存进行通信和数据共享。
  5. 并发性:线程可以实现更加高效的并发编程,因为线程之间的切换开销小且可以共享进程的资源;而进程在并发编程中相对较重,因为需要处理进程间通信和资源分配等问题。

js是单线程还是多线程的

javaScript的单线程特性

JavaScript在浏览器和Node.js环境中是单线程的,这意味着它在同一时间只执行一个任务。

这种设计主要是为了简化代码逻辑,避免并发导致的复杂性,并减少潜在的错误。

由于JavaScript可以操作DOM,如果多个线程同时操作DOM,可能会导致浏览器混乱。因此,单线程模型可以确保DOM操作的一致性和安全性。

事件循环和异步操作

虽然JavaScript是单线程的,但它通过事件循环机制来处理异步操作。当执行一个函数时,它会被推入调用栈=,执行完后出栈。如果遇到异步操作(如网络请求、定时器等),JavaScript会将这些操作放入任务队列。事件循环不断检查调用栈是否为空,如果栈为空,它会从任务队列中取出下一个任务并将其推入栈中执行。这种方式使得JavaScript能够处理异步事件,而不会阻塞主线程。

Web Workers支持多线程

虽然JavaScript在主线程上是单线程的,但它通过Web Workers API支持多线程。Web Workers允许在后台线程中运行JavaScript代码,进行并行处理。这些后台线程与主线程(UI线程)相互独立,彼此之间通过消息传递(postMessage)进行通信。这种方式可以提高应用程序的性能,特别是在处理计算密集型任务时,而不会阻塞UI线程。

总结

因此,可以说JavaScript在单线程的基础上,通过事件循环机制实现了异步操作,并通过Web Workers支持了多线程的并行处理。

浏览器渲染进程的线程有哪些

浏览器渲染进程主要负责将HTML、CSS和JavaScript等文件解析为用户可以交互的网页。这个进程是多线程的,主要包括以下几个关键线程:

  1. GUI渲染线程(Rendering Thread)
    • 负责渲染页面,包括解析HTML、CSS,构建DOM树、CSSOM树、渲染树,以及绘制页面。
    • 当界面需要重绘或由于某种操作引发回流时,该线程就会执行。
    • GUI渲染线程和JS引擎线程是互斥的,当JS引擎执行时,GUI线程会被挂起,GUI更新会被保存在一个队列中,等到JS引擎空闲时立即被执行。
  2. JS引擎线程(JavaScript Engine Thread)
    • 也称为JS内核,负责处理JavaScript脚本程序,解析JavaScript脚本并运行代码。
    • 一个Tab页中无论什么时候都只有一个JS引擎线程在运行JavaScript程序。
    • 由于GUI渲染线程与JS引擎线程的互斥关系,如果JS执行时间过长,会造成页面的渲染不连贯,导致页面渲染加载阻塞。
  3. 事件触发线程(Event Dispatch Thread)
    • 属于浏览器而不是JS引擎,负责处理JavaScript代码中的事件,控制事件循环。
    • 当JS引擎执行代码块(如setTimeout)或来自浏览器内核的其他线程(如鼠标点击、AJAX异步请求等)触发事件时,会将对应任务添加到事件触发线程中。
    • 当对应的事件符合触发条件时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。
  4. 定时器线程(Timer Thread)
    • 负责定时器功能,如setIntervalsetTimeout
    • 浏览器定时计数器并不是由JS引擎计数的,因为JS引擎是单线程的。如果处于阻塞状态,就会影响计时的准确性。因此,使用单独线程来计时并触发定时器。
    • 计时完毕后,定时器线程会将任务添加到事件队列中,等待JS引擎空闲后执行。所以,定时器中的任务在设定的时间点不一定能够准时执行,定时器只是在指定时间点将任务添加到事件队列中。
  5. 异步HTTP请求线程
    • 负责处理网络请求,如通过XMLHttpRequest发起的异步请求。
    • 检测到状态变更时,如果设置有回调函数,异步线程会产生状态变更事件,并将回调函数放入事件队列中,等待JS引擎空闲后执行。
相关推荐
活宝小娜2 分钟前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点4 分钟前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow6 分钟前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o7 分钟前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
开心工作室_kaic1 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
刚刚好ā1 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
沉默璇年2 小时前
react中useMemo的使用场景
前端·react.js·前端框架
yqcoder2 小时前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
2401_882727573 小时前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架
Swift社区3 小时前
LeetCode - #139 单词拆分
算法·leetcode·职场和发展