目录
1. http缓存机制
HTTP缓存机制旨在通过减少网络请求的数量来加快网页加载速度,同时降低服务器负载。它主要通过浏览器和服务器之间的协议头信息来实现。以下是HTTP缓存的主要机制和相关头部字段:
缓存机制
强缓存:通过
Cache-Control
和Expires
头部控制。- Cache-Control:提供了更细粒度的缓存控制,包括但不限于:
no-cache
:要求在使用缓存前必须向服务器验证资源是否有更新。no-store
:禁止缓存,每次都要从服务器获取最新数据。public
:指示响应可以被任何缓存存储。private
:指示响应仅对单个用户有效,不能被共享缓存存储。max-age=<seconds>
:指定资源被认为新鲜的最大时间(秒)。
- Expires:指定了一个绝对的过期时间,格式为GMT时间。由于其依赖于客户端时钟准确性,现代实践中更多使用
Cache-Control
。
- Cache-Control:提供了更细粒度的缓存控制,包括但不限于:
协商缓存:当强缓存未命中或根据策略需要重新验证时,使用
ETag
和/或Last-Modified
进行缓存验证。- ETag:提供了一个唯一的标识符(通常是哈希值),用于判断资源是否发生变化。
- If-None-Match:随请求发送给服务器,包含之前收到的ETag值。如果资源未变化,服务器返回304 Not Modified状态码,客户端继续使用缓存。
- Last-Modified:指示资源最后修改的时间。
- If-Modified-Since:随请求发送给服务器,包含上次收到的Last-Modified时间。逻辑同If-None-Match。
流程概述
- 当用户首次访问一个页面时,浏览器会从服务器下载资源,并根据响应头部设置本地缓存。
- 在后续访问中,浏览器首先检查强缓存是否可用且未过期。如果是,则直接使用缓存,不会发起请求。
- 如果强缓存已过期或者根据Cache-Control指示需要验证,浏览器将发起条件请求(带有If-None-Match或If-Modified-Since头部)到服务器进行验证。
- 服务器根据请求头部中的信息决定资源是否自上次请求后发生改变。如果没有变化,返回304状态码;如果有变化,则返回新的资源以及相应的缓存指令。
通过合理配置这些头部,可以有效地利用HTTP缓存机制提升用户体验,同时减轻服务器负担。不过需要注意的是,缓存策略应根据实际情况精心设计,以避免因缓存导致的数据不一致问题。
2. 常见的http状态码
1xx(信息性状态码)
- 100 Continue:客户端应继续其请求。
- 101 Switching Protocols:服务器已理解客户端的请求,并将通过升级协议进行切换。
2xx(成功状态码)
- 200 OK:请求成功,所希望的回应头或数据体将随此回应返回。
- 201 Created:请求已被实现,且有一个新的资源依据请求的需要而建立。
- 204 No Content:服务器成功处理了请求,但没有返回任何内容。
3xx(重定向状态码)
- 301 Moved Permanently:请求的资源已永久移动到新位置,并且未来任何对此资源的引用都应该使用本响应返回的URI。
- 302 Found:请求的资源临时从不同的URI响应请求。
- 304 Not Modified:资源未被修改,可以使用缓存的版本。
4xx(客户端错误状态码)
- 400 Bad Request:由于语法无效,服务器无法理解该请求。
- 401 Unauthorized:当前请求需要用户验证。
- 403 Forbidden:服务器理解请求但拒绝执行。
- 404 Not Found:服务器找不到请求的网页。
- 405 Method Not Allowed:禁用请求中指定的方法。
5xx(服务器错误状态码)
- 500 Internal Server Error:服务器遇到未知情况阻止它完成请求。
- 501 Not Implemented:服务器不具备完成请求的功能。
- 502 Bad Gateway:作为网关或代理角色的服务器从上游服务器接收到无效响应。
- 503 Service Unavailable:服务器目前无法使用(因为超载或停机维护)。
- 504 Gateway Timeout:作为网关或代理角色的服务器未能及时从上游服务器获得响应。
了解这些状态码有助于快速定位问题所在,优化Web应用的性能和可靠性。
3. http和https的区别?
- HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。
- 使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。证书颁发机构如:Symantec、Comodo、GoDaddy 和 GlobalSign 等。
- HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
- http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
- HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,所以,要比较 HTTPS 比 HTTP 要更耗费服务器资源。
4. 跨域的解决方案
跨域资源共享(CORS, Cross-Origin Resource Sharing)是一种机制,它使用额外的HTTP头部让浏览器能够从一个源请求另一个源的资源。以下是几种常见的跨域解决方案:
CORS(跨域资源共享):
- 服务器通过设置特定的HTTP响应头来允许某些或所有来源的访问。例如,
Access-Control-Allow-Origin
头部可以指定哪些域名可以访问资源。 - 可以配置更复杂的规则,比如允许特定的方法(GET、POST等),或者允许携带凭证(如cookies)的请求。
- 服务器通过设置特定的HTTP响应头来允许某些或所有来源的访问。例如,
JSONP(JSON with Padding):
- JSONP是一种利用
<script>
标签不受同源策略限制的特点实现跨域请求的方法。 - 它的工作原理是动态创建一个
<script>
元素,并设置其src
属性为目标跨域URL,该URL返回的数据会被包装在一个函数调用中,这个函数在当前页面定义。 - 注意:由于安全性问题,现代应用推荐使用CORS而非JSONP。
- JSONP是一种利用
代理服务器:
- 如果无法直接从浏览器端进行跨域请求,可以在服务器端搭建一个代理服务。
- 浏览器向同一域下的代理服务器发送请求,代理服务器再向目标服务器发起请求并转发结果给浏览器。
- 这种方法避免了浏览器的同源策略限制。
WebSocket:
- WebSocket协议提供了一种新的途径来建立客户端和服务器之间的交互,且不受同源策略的限制。
- 当需要实时通信时,这是一种有效的解决跨域问题的方法。
修改
.htaccess
文件(适用于Apache服务器):- 可以通过编辑
.htaccess
文件添加必要的CORS头部信息,使服务器支持跨域请求。
- 可以通过编辑
iframe与postMessage API:
- 使用iframe嵌入外部内容,并结合HTML5的
postMessage
API实现跨文档消息传递。 - 这样可以让不同源的文档之间安全地交换字符串消息。
- 使用iframe嵌入外部内容,并结合HTML5的
选择哪种方案取决于具体的应用场景和需求。对于大多数情况,推荐使用CORS作为首选解决方案,因为它既符合标准,又具有良好的兼容性和灵活性。如果需要支持老旧浏览器或者有特殊的跨域需求,则可能需要考虑其他方法。
CORS注解
参考:https://blog.csdn.net/Do_LaLi/article/details/117568142
@CrossOrigin的使用:
- 在方法上,表示该方法可以实现跨域请求。
- 在类上,表示该类中所有方法都可实现跨域请求。
@CrossOrigin的两个参数:
- origins:允许可访问的域列表
- maxAge:准备响应前的缓存持续的最大时间(以秒为单位)。
示例:@CrossOrigin(origins = "http://localhost:8082", maxAge = 3600)
5. 浏览器存储,他们的区别?
- localStorage:永久保存,以键值对保存,存储空间5M
- sessionStorage:关闭页签/浏览器时清空
- cookie:随着请求发送,通过设置过期时间删除
- session:保存在服务端
localStorage/sessionStorage是window的属性,cookie是document的方法
6. 页面优化
1、某个页面加载较慢,从哪些方向分析、解决问题?
传统页面
首先判断是接口慢,还是页面慢。如果接口慢,后端优化。
如果前端页面加载慢,看是否是因为图片等资源过大,尝试替换不同格式体积的图片。定位是否是某些数据处理的函数,比较耗时。或者是否循环操作DOM,js生成dom后再批量插入。
如果页面直接卡死,就需要分析是否内存泄漏。比如大屏展示的定时刷新卡死,排查思路可如下:
使用chrome的任务管理器,操作页面观察的内存占用的变化。定位到是哪些操作,哪块代码导致内存占用飙升。
因为js并没有直接释放缓存的语法,只有靠浏览器的垃圾回收机制自动清理。我们需要做的是及时给不需要的变量赋空。
特别注意大数据的循环实例化后,变量是否及时赋空。定时器等闭包方法中是否存在内存泄漏,循环渲染地图时,是否先将之前地图数据清空等。
单页面应用
单页面一般不会某个页面加载慢,一般都集中在首屏加载时白屏较久。处理方法可参考上文中
2、使用缓存
- 有些接口没必要每次打开页面都请求,可用cookie计时。某个时间段内不重新获取。
- 某些数据初始化时加载一次即可,可通过cookie计时,某个时间段内不用请求。
- 某些数据可用localstorage存储,默认填充input,更新时才重写缓存。这个只是用户体验好些
7. 计算机原理
1、进程和线程的关系?
进程(Process)和线程(Thread)是操作系统中两个重要的概念,它们之间存在密切的关系。进程:
进程是程序执行的实例,是操作系统资源分配的基本单位。
每个进程都有独立的地址空间、代码、数据和系统资源。
进程之间相互独立,彼此不受影响。
线程:线程是进程内的执行单元,是操作系统调度的基本单位。
同一进程内的多个线程共享相同的地址空间和系统资源。
线程之间可以方便地进行通信和数据共享。
关系:一个进程可以包含多个线程,这些线程共享进程的资源,包括内存、文件句柄等。
同一进程内的线程之间可以通过共享的内存空间进行通信和数据交换,这使得线程间的协作变得更加高效。
总的来说,进程和线程之间是包含关系,一个进程可以拥有多个线程,而线程则是在进程内执行的单元。通过线程的使用,可以更加高效地利用系统资源,提高程序的并发性和响应性。
8. GET和POST请求方式的区别
数据传输方式
- GET:将参数附加在URL后面作为查询字符串发送到服务器。例如:
http://example.com/page?key1=value1&key2=value2
- POST:通过请求体发送数据,参数不会显示在URL中。
数据大小限制
- GET:由于数据是附加在URL中的,而浏览器对URL长度有限制(不同浏览器限制不同),因此GET请求的数据大小也受到限制,通常建议不超过2048个字符。
- POST:理论上可以发送大量数据,受限于服务器配置和内存情况。
安全性
- GET:因为数据直接暴露在URL中,所以相对不安全,不适合传输敏感信息如密码等。
- POST:数据在请求体中,相对更安全一些,但也不是绝对安全,仍需使用HTTPS协议保证数据传输的安全性。
缓存
- GET:请求可被浏览器缓存,适合用于获取数据的操作,如搜索内容。
- POST:请求一般不会被缓存,更适合用于提交数据的操作,如表单提交。
幂等性
- GET:应该是幂等的,即多次相同的GET请求应该产生相同的结果,不会影响服务器状态。
- POST:不是幂等的,每次请求可能会导致服务器状态的变化(比如数据库记录的增加)。
用途
- GET:适用于获取资源,不应有副作用。
- POST:适用于提交数据,可能会改变服务器上的资源状态。
选择GET还是POST应根据具体的应用场景来决定。如果只是简单地获取数据且不需要保密,GET通常是不错的选择;如果涉及到用户输入、文件上传或任何可能修改服务器端资源的操作,则应使用POST。
9. script标签,async和defer的作用
在HTML中,<script>
标签用于加载和执行JavaScript代码。为了优化网页的性能,避免脚本阻塞页面的渲染或资源加载,async
和defer
属性被引入。它们的作用是控制脚本的加载和执行行为。
1. 默认行为(无 async
和 defer
)
- 如果
<script>
标签没有指定async
或defer
属性:- 加载:浏览器会立即加载脚本,并且阻塞 HTML 的解析。
- 执行:一旦脚本加载完成,浏览器会立即执行脚本,然后继续解析剩余的HTML内容。
- 问题:这种方式可能会导致页面渲染延迟,尤其是在脚本文件较大或网络较慢的情况下。
<script src="example.js"></script>
2.
async
属性
作用:
- 脚本异步加载,不会阻塞HTML的解析。
- 脚本加载完成后,会立即执行,即使HTML尚未完全解析。
- 多个带有
async
属性的脚本之间的执行顺序不保证,谁先加载完成谁先执行。适用场景:
- 适用于独立的脚本(如统计分析脚本、广告脚本等),这些脚本不需要依赖其他脚本或DOM结构。
<script src="example.js" async></script>
- 特点:
- 不会阻塞HTML解析。
- 执行时机不确定(取决于脚本的加载速度)。
3.
defer
属性
作用:
- 脚本异步加载,不会阻塞HTML的解析。
- 脚本加载完成后,会等待HTML解析完成后才执行。
- 多个带有
defer
属性的脚本会按照它们在HTML中的顺序依次执行。适用场景:
- 适用于需要操作DOM但又不想阻塞页面渲染的脚本(如主程序逻辑)。
<script src="example.js" defer></script>
- 特点:
- 不会阻塞HTML解析。
- 执行顺序是确定的,按照脚本在HTML中的顺序执行。
- 执行时机是在HTML解析完成后、
DOMContentLoaded
事件之前。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Script Example</title>
<script src="script1.js" async></script>
<script src="script2.js" defer></script>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
行为分析:
script1.js
(async):- 异步加载,加载完成后立即执行。
- 可能会在页面渲染之前执行,也可能在渲染之后执行。
- 如果
script1.js
比script2.js
先加载完成,则会先执行。
script2.js
(defer):- 异步加载,但会等待HTML解析完成后按顺序执行。
- 即使
script2.js
比script1.js
先加载完成,也会等到HTML解析完成后再执行。
6. 总结
- 如果脚本之间有依赖关系,或者需要确保脚本在HTML解析完成后执行,使用
defer
。 - 如果脚本是独立的,且不需要依赖HTML解析结果,使用
async
。 - 如果脚本必须同步加载并立即执行(如某些关键逻辑),则不加
async
或defer
。
通过合理使用 async
和 defer
,可以显著提升网页的加载速度和用户体验。
10. 重绘和重排(回流)的区别
重排(Reflow)
重排是指当浏览器为了重新渲染部分或全部文档,需要重新计算元素的几何属性(如宽度、高度、位置等)的过程。任何影响到元素布局的操作都会导致重排。例如:
- 改变窗口大小
- 添加或删除可见的DOM元素
- 改变内容,比如文本改变或者图片尺寸变化
- 浏览器窗口的滚动
重排是一个昂贵的过程,因为它会触发页面中其他元素的布局更新,有时甚至是整个页面的重新布局。
重绘(Repaint)
重绘发生在不需要重新计算布局但需要重新绘制元素的情况下。这通常是因为某些只影响元素外观而非其大小或位置的属性发生了变化,比如:
- 改变元素的颜色
- 改变背景图像
- 可见性(visibility)的变化
相比于重排,重绘的成本较低,因为它不涉及重新计算布局,但它仍然消耗资源,尤其是在大规模发生时。
总结
- 重排(Reflow):涉及到元素尺寸或位置的改变,需要重新计算布局,成本较高。
- 重绘(Repaint):只涉及元素外观的改变,不需要重新计算布局,成本相对较低。
优化网站性能的一个关键点就是尽量减少重排和重绘的次数。通过批量修改DOM、使用CSS3硬件加速以及避免频繁的布局操作,可以有效提升网页的响应速度和用户体验。
11. Dom事件流的顺序?什么是事件委托?
当页面上的一个元素被点击时,先从document向下一层层捕获到该元素。然后再向上冒泡,一层层触发。
事件委托是将事件写在父级元素上,e.target是事件捕获时那个最小的元素,即选中的元素。所以可以根据e.target操作选中的元素。这样不需要给每个子元素绑定事件,代码更加简约。
DOM(文档对象模型)事件流描述了事件在页面中触发和传播的顺序,它包括三个阶段:捕获阶段、目标阶段和冒泡阶段。
1. 捕获阶段(Capture Phase)
- 事件从文档的根节点(
document
)开始,依次向下查找,直到找到事件目标元素的父元素。在这个过程中,事件会依次经过各级祖先元素。- 例如,当你点击一个页面中的按钮时,事件会从
document
开始,经过html
、body
等元素,逐渐向下查找,直到按钮的父元素。2. 目标阶段(Target Phase)
- 当事件到达目标元素时,就进入了目标阶段。目标元素就是实际触发事件的元素,比如上面提到的按钮。
- 在这个阶段,事件会直接作用于目标元素。
3. 冒泡阶段(Bubbling Phase)
- 事件从目标元素开始,依次向上传播,经过各级祖先元素,直到到达文档的根节点(
document
)。- 继续以点击按钮为例,事件在目标阶段作用于按钮后,会依次经过按钮的父元素、父元素的父元素,一直传播到
document
。在实际的事件绑定中,可以通过
addEventListener
方法的第三个参数来指定事件处理函数是在捕获阶段还是冒泡阶段执行。如果第三个参数为true
,则事件处理函数在捕获阶段执行;如果为false
或者省略该参数,则事件处理函数在冒泡阶段执行。事件委托
事件委托(Event Delegation)是一种利用事件冒泡原理的技术,它允许将事件处理程序绑定到一个父元素上,而不是直接绑定到每个子元素上。当子元素上的事件触发时,事件会冒泡到父元素,然后由父元素上的事件处理程序来处理。
优点
- 减少内存占用:如果有大量的子元素需要绑定相同的事件处理程序,直接绑定到每个子元素上会占用大量的内存。使用事件委托只需要在父元素上绑定一个事件处理程序,从而减少内存开销。
- 动态添加子元素时无需重新绑定事件:当动态添加新的子元素时,由于事件处理程序是绑定在父元素上的,新的子元素会自动继承该事件处理程序,无需重新为每个新元素绑定事件。
12、防抖/节流的区别?
区别:防抖只会在最后一次事件后执行触发函数,节流不管事件多么的频繁,都会保证在规定时间段内触发事件函数。
- 防抖:
原理是维护一个定时器,将很多个相同的操作合并成一个。规定在delay后触发函数,如果在此之前触发函数,则取消之前的计时重新计时,只有最后一次操作能被触发。例如:实时搜索的input,一直输入就不发送。
let input = document.querySelector("input");
let time = null;//time用来控制事件的触发
input.addEventListener('input',function(){
//防抖语句,把以前的定时删除,只执行最后一次
if(time !== null){
clearTimeout(time);
}
time = setTimeout(() => {
console.log(this.value);//业务实现语句,这里的this指向的是input
},500)
})
封装成通用函数
- 防抖逻辑可以封装成一个通用的工具函数,方便复用。
function debounce(fn, delay) {
let timer = null;
return function(...args) {
if (timer !== null) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
input.addEventListener('input', debounce(function() {
console.log(this.value);
}, 500));
- 节流:
原理是判断是否达到一定的时间来触发事件。某个时间段内只能触发一次函数。例如:在指定的时间内多次触发无效
//节流
function throttle(fn, time) {//连续触发事件 规定的时间
let flag = false;
return function () {
//使用标识判断是否在规定的时间内重复触发了函数,没有就触发,有就不触发
if (!flag) {//不为假时 执行以下
fn();//触发事件
flag = true;//为真
setTimeout(() => {//超时调用(在规定的时间内只执行一次)
flag = false;
}, time);
}
}
}
mybtn.onclick = throttle(btn, 3000);//单击事件 节流(btn,3s时间)
13、margin高度塌陷
在 CSS 中,margin 高度塌陷是指在一些特定情况下,元素的margin
属性没有按照预期产生垂直方向的间距,导致元素之间的距离出现异常。以下是对其产生原因及解决方案的介绍。
产生原因
- 父子元素 margin 重叠:当父元素没有边框、内边距或其他能阻止 margin 传递的属性时,子元素的 margin-top 或 margin-bottom 会与父元素的相应 margin 合并,导致父元素的高度塌陷。例如,一个父元素包含一个子元素,子元素设置了
margin-top: 20px
,如果父元素没有设置border-top
、padding-top
等属性,那么子元素的margin-top
会作用在父元素上,使父元素顶部出现 20px 的空白,而不是子元素与父元素之间有 20px 的间距。 - 相邻兄弟元素 margin 合并:垂直方向上相邻的两个兄弟元素,它们的
margin
值会取其中较大的值作为它们之间的间距,而不是两者相加。例如,一个元素有margin-bottom: 20px
,它下面的兄弟元素有margin - top: 10px
,那么这两个元素之间的实际间距是 20px,而不是 30px。
解决方案
- 为父元素设置边框或内边距:给父元素添加
border
或padding
,可以阻止子元素的margin
与父元素的margin
合并。例如,设置border-top: 1px solid transparent
或padding - top: 1px
。 - 使用 overflow:hidden:给父元素设置
overflow: hidden
,可以创建一个新的块级格式化上下文,从而防止margin
塌陷。但要注意,这可能会导致子元素中超出父元素范围的内容被隐藏。 - 使用 flex 或 grid 布局:在父元素上应用
display: flex
或display: grid
,可以改变元素的布局方式,避免margin
塌陷问题。因为 flex 和 grid 布局有自己的一套布局规则,会影响margin
的行为。 - 分开设置 margin:对于相邻兄弟元素,尽量避免同时设置上下方向的
margin
。可以根据实际情况,只在其中一个元素上设置margin
,以达到期望的间距效果。