| 数据存储大小 | 4kb | 5mb | 5mb | 无限 |
| 与服务端的通信 | 会一直携带在请求头 | 不参与下 | 不参与 | 不参与 |
PS:没有大量的数据需求的话,可以使用localStorage和sessionStorage,对于不怎么改变的数据,尽量使用localStorage。
31.2 什么是Service Worker
-
Service Worker是运行在浏览器背后的独立线程,一般可以用来实现缓存功能,使用Service Worker的话,传输协议必须使用HTTPS。
-
使用Service Worker实现缓存一般分为三个步骤:
1)首先要注册Service
2)监听install,拿到需要缓存的文件
3)下次用户访问的时候就可以通过拦截请求方式查询是否存在缓存,存在缓存的话就可以直接读取缓存文件,否则就去请求数据
32.浏览器中的缓存机制
-
缓存可以是性能优化中简单高效的一种方式
-
对于一个数据请求,分为3个阶段,分为网络请求、后端处理、浏览器响应。浏览器缓存可以帮助我们在第一和第三步中优化性能。比如直接使用缓存而不发请求,或者发请求但后端的数据与前端一致,那么就没有必要再将数据回传回来,这样就减少可数据响应。
接下来我们将通过以下几个方面来探讨浏览器的缓存机制
-
缓存位置
-
缓存策略
-
实际场景应用缓存策略
32.1 缓存位置
我知道的浏览器的缓存位置有Service Worker、网络请求,并且有各自的优先级,当一次查找缓存并且都没有命中的时候,才会请求网络。
32.2 缓存策略
通常浏览器的缓存策略可以分为两种:强缓存和协商缓存。并且这两种缓存策略都是通过设置 HTTP Header 来实现的
1)强缓存(有两种设置方式)
-
Expires:缓存受限于本地的时间
-
Cache-Control:通过max-age来设置缓存的时间期限
2)协商缓存(两种设置方式)
简单的说,如果缓存过了,就需要发起请求验证资源是否更新。即当浏览器发送请求验证时,如果资源没有发生改变,那么服务器就返回304状态码,并更新浏览器的缓存有效期。(相当于浏览器和服务器进行协商,是否返回新的数据)
- Last-Modified
Last-Modified表示本地文件最后修改日期,当 Last-Modified的值发送给服务器,循环服务器在该日期后资源是否有变更,有则返回新的资源,否则返回304状态码
- ETag
当ETag的值发送给服务器,询问该资源是否有更新,有则返回新的资源(并且ETag的资源比Last-Modified高)
32.3 实际场景应用缓存策略
一般来说,现在都会使用工具来打包代码,那么我们可以对文件名进行哈希处理,只有当代码修改之后生产新的文件名。基于此,我们就可以给代码设置缓存有效期一年Cache-Control:max-age=3153600,这样只有html文件中引入的文件名发生了改变,才回去下载新的代码,否则就一直使用缓存。
33. 插入几万个DOM,如何实现页面不卡顿?
-
使用分页技术
-
若不分页,则使用虚拟滚动技术(比如elment-ui中的scrollbar可以实现)
虚拟滚动:原理时只渲染可视区域内的内容,非可视区的则不渲染,当用户在滚动的时候就实时去替换渲染的内容。
34.什么情况下会产生渲染堵塞?
我们知道,在浏览器的渲染线程和JS引擎线程时互斥的,因此在渲染时,若遇到script标签时,则此时会渲染会停止下来,等待script代码加载完毕,再从暂停的地方重新渲染。也就是说,当你想首屏渲染越快,那么就不应该再首屏加载js文件,也就是建议将script标签放在body标签底部的原因。当然,你也可以给script标签添加defer或者async属性,那么此时的script可以放在任意位置,因为此时js文件会并行下载,若时defer,会等待页面渲染结束才执行,而async会在加载完毕之后立即执行。
只是defer和async表示js文件的加载和解析不会阻塞渲染。‘
35. 重绘和回流
-
重绘是节点更改了外观而不影响布局,比如更改元素的color属性
-
回流是改变了节点的布局或者几何属性,比如改变元素的宽高等属性
-
回流必然发生重绘,重绘不一定引发回流。
36. 减少重绘和回流
1.使用transform替换top
2.使用visibility替换display:none,因为前者只会引发重绘,而后者会引发回流
3.少用table布局,因为table布局很小的一个改动会引发整个table的重新布局
4.将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点。(比如video标签,浏览器会自动将该节点变为图层)
37. 什么是XSS攻击?如何防止XSS攻击?
1.XSS攻击
-
XSS(Cross-Site Scripting)—跨站脚本攻击,简称XSS,是一种代码注入攻击,攻击者通过在目标网址注入恶意脚本,使之在用户的的浏览器上运行。利用这些恶意脚本,攻击者获取用户敏感信息如Cookie、SessionID等,进而危害数据安全
-
XSS的本质:恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行
2. 如何防止
由于问题的源头是js代码的注入,那么我们便想办法不让js生效
方式1:使用转义字符
即需要注意两头的防范:
1)输入
在提交表单时,前端最好将文本内容转成html实体编码,也就是过滤掉
2)输出
在显示文本时,最好也要做一次html实体编码转换后再显示,防止
方式2:CSP建立白名单
建立白名单,即是明确告诉浏览器哪些外部资源可以加载和执行。(我们只需要配置规则,如何拦截是由浏览器自己实现的)
通常可以通过两种方式来开启CSP:
1)设置HTTP Header中的Content-Security-Policy
2)设置meta标签的方式
38. 什么是CSRF攻击?如何防范CSRF攻击?
1. CSRF攻击
CSRF中文名为跨站请求伪造,原理是攻击者诱导受害者进入第三方网站,在第三方网站中向被攻击网站发送跨站请求,利用受害者在被攻击已获取的注册凭证,绕过后台的验证,达到冒充用户对被攻击的网站执行某项操作的目的。
几种常见的攻击类型
1)GET类型的CSRF利用非常简单,只需要一个HTTP请求,一般会这样利用
![](https://i-blog.csdnimg.cn/blog_migrate/2c0443e4e560dbb7800244d0ccfa7304.png)
在受害者访问这个img页面之后,浏览器会自动向https://i-blog.csdnimg.cn/blog_migrate/2c0443e4e560dbb7800244d0ccfa7304.png
发送一次http请求,bank.example就会收到包含受害者登录信息的一次跨域请求(因此此时受害访问了A网站,那么其是包含着认证信息的,攻击者利用这一特性,隐形中让受害者向上网站(B)发起HTTP请求,那么此时请求头自然也会包含了受害者的认证信息,那么攻击者的目的便达到!)
2. 如何防范
CSRF通常是第三方网站发起的,被攻击者的网站无法防止攻击的发生,只能通过增强自己的网站针对CSRF的防护能力来提升安全性
SCRF的两个特点:
-
SCRF(通常)发生在第三方域名
-
SCRF攻击者不能取到Cookie等信息,只是冒用
针对以上两个特点,我们可以专门指定防护策略,如下:
-
阻止不明外域的访问
-
同源检测
-
Samesite Cookie
-
提交时要附加本域才能获取信息
-
CSRF Token
-
双重Cookie验证
验证Referer
- 可以通过Referer来判断该请求是否为第三方网站发起的,若是,则阻止。
SameSite
- 可以对Cookie设置SameSite属性,该属性表示Cookie不随跨域请求发送,可以大程度减少CSRF的攻击,但是该属性目前不是所有浏览器都支持
CSRF Token
-
前面讲的CSRF的一特征是,攻击者无法直接窃取到用户的信息(Cookie、Header,网站内容等,仅仅是冒用Cookie中的信息)
-
而CSRF攻击之所以能成功,是因为服务器误把攻击者发送的请求当成了用户的请求,那么所有用户请求都会携带一个CSRF攻击者无法获取到的Token,服务器便可以通过校验请求是否携带正确的Token,来把正常的请求和攻击请求区分开来,也可以防范CSRF的攻击
参考文章:https://my.oschina.net/meituantech/blog/2243958
29. 什么是点击劫持?如何防范点击劫持?
点击劫持就是攻击者利用iframe将受害者网站嵌入自己的网页中,并将iframe设置为透明,在页面中透出一个按钮诱导用户点击。
通常可以使用以下两种方式进行防御:
1)设置HTTP响应头:X-FRAME-OPTIONS
这个响应头主要是用来防御iframe嵌套的点击劫持,其有三个可选值,分别是:
-
DENY:表示页面不允许通过iframe的方式展示
-
SAMEORINGIN:表示页面可以在相同的域名下通过iframe的方式展示
-
ALLOW-FROM:表示页面可以在指定来源iframe中展示
2)通过JS防御
因为有些浏览器不支持1)的方式
JS防御的原理是通过iframe的方式加载页面时,攻击者的页面直接不显示内容。
30. 性能优化
1.在请求以及文件大小方面
-
尽可能的将js、css文件合并为一个文件,减少了向服务器发送请求(webpack)
-
若浏览器支持,尽可能使用webp格式的图片代替其他图片格式
-
尽量使用字体图标或者SVG图代替传统的png图
-
尽量使用精灵图或者说时雪碧图(一方面可以减少向服务器发送请求,另一方面则是降低了资源占用空间大小)
-
可以适当的使用缓存技术,比如对于不怎么发生变化的数据,使用h5新增等的localstorage、sessionStorage,以减少发送请求的次数
2.对于代码优化相关
-
闭包-------在js中尽量减少使用闭包(因为闭包所在的上下文不会被释放)
-
重绘和回流-----减少对DOM的操作,主要时减少DOM的重绘和回流
-scc与js代码的位置----- 把css代码放在body上,把js代码放在body下面(以提高首屏加载的速度,当然也可以对script标签使用defer和async属性)
-
css的导入方式-----css的导入尽量减少使用@import,因为@import是同步操作,可以使用link导入
-
懒执行-----对某些特定的逻辑代码进行懒执行操作。主要用于某些耗时的逻辑操作,且不需要在首屏就使用时,便可以使用定时器或者时间调用来唤醒。
-
懒加载-------懒加载是将不关键的资源延后加载
31. Webpack的性能优化
3.减少webpack的打包时间
1.优化Loader
- 对于Loader来说,影响打包效率首当其冲必属Bable,因为Bable会将代码转为字符串生产AST,然后再对AST继续进行转变量再生成新的代码。当你的项目越大,那么转换代码就越多,效率就越低下。因此我们一般只对js文件使用Bable转换格式(可以再配置文件中通过rules来进行配置。
2.实现按需加载
比如在一个SPA项目中,项目会有十几个甚至更更多的路由页面,我们可以实现按需加载,以减少一些不必要代码的加载
32. 路由原理(什么是前端路由?两种实现方式有什么区别?)
1. 前端路由
- 前端路由的本质是根据url的不同,匹配路由规则的变化,然后显示相应的页面,并且不需要重新刷新页面。目前前端使用的路由只有两种方式(Hash模式和History模式)
1)Hash模式
Hash模式是根据#后面哈希值的变化时,触发了hashchange事件来监听到url的变化,从而进行页面的跳转。并且无论哈希值怎么样变化,服务器接收到的url永远都是#前面部分的url
如www.test.com/#/---------->www.test.com
2)History模式
History模式是H5新推出来的功能,主要使用history.pushState和history.repalceState改变url,同样,通过History模式改变url也不会引起页面的刷新,只会更新浏览器的历史记录
3)两种方式的区别
-
Hash模式只可以更改#后面的内容,History模式可以通过API设置任意的同源URL
-
Hash不需要后端配置,兼容性好。History模式再用户手动输入地址或者刷新的时候会发送url请求,后端需要配置index.html页面用于匹配不到的静态页面资源。
33.谈谈你对webpack的看法
我当时使用webpack的主要原因是为了简化页面依赖的管理,并且通过将其打包为一个文件来降低页面加载时请求的资源数。
我认为webpack的主要原理是,它将所有的资源看成一个模块,并且把页面逻辑当成一个整体,通过一个给定的入口文件,webpack从这个文件开始,找到所有的依赖文件,将这个依赖文件模板通过loader和plugins处理后,然后打包在一起,最后输出一个浏览器可以识别的js文件。
34. 谈谈你理解的函数式编程?
简单的说,函数式编程是一种编程范式,也就是如何编写程序的方法论
它具有以下特性:闭包和高阶函数、惰性计算、递归
35. 异步编程的实现方式?
第一种最常见的就是回调函数的方式,使用回调函数的方式有一个缺点就是,多个回调嵌套的时候会造成回调函数地狱,上下两层的回调函数间的代码耦合度太高,不利于代码的可维护。
第二种是Promise的方式,使用Promise的方式可以将嵌套的回调函数作为链式调用,但是使用这种方法,有时会造成多个then的链式调用,可能会造成代码的语义不够明确。
第三种是使用async函数的形式,它内部自带执行器,当函数内部执行一个awiait语句的时候,如果语句返回一个promise对象,那么函数就会将等待promise对象的状态变为resolve后再继续向下执行。因此我们可以将异步逻辑,转换成同步的顺序来书写,并且这个函数可以自动执行。
36.URI和URL的区别
URI:统一资源标识符
URL:统一资源定位符
URN:统一资源名称
PS:‘
1)URI指的是统一标识符,用唯一的标识来确定一个资源,它是一种抽象的定义,也就是说,不管使用什么方法来定义,只要能唯一标识一个资源,就可以成为URI
2)URL和URN是URI的子集,URL可以理解为使用地址来标识资源,URN可以理解为使用名称来标识资源。
37.get和post请求在缓存方面的区别
缓存一般适用于那些不会更新服务端数据的请求,一般get请求都是查找请求,不会对服务器资源造成修改,而post请求一般都会对服务器数据造成修改,所以,一般会对get请求进行缓存,很少会对post请求进行缓存。
38. 图片懒加载和预加载
相关知识点:
懒加载:懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数
预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染
懒加载:
懒加载也叫做延迟加载,即是当用需要访问时,在去加载,这样可以提高网站首屏加载速度,提升用户的体验,并且还可以减少服务器的压力。它适用于图片很多时,页面很长的电商网站的场景。懒加载的实现原理是,将页面上的图片的src属性设置为空字符串,将图片的真是路径保存在一个自定义的属性中,当页面滚动时候,进行判断,如果图片进入页面可视区域,则从自定义的属性中取出真是路径赋值给图片的src属性,以此来实现图片的延迟加载。(比如在vue中使用v-lazy)
预先加载:
预先加载指得是将所需的资源提前加载到本地,这样后面在需要用到时就直接从缓存资源通过预加载能够减少用户的等待时间,提高用户的体验。我了解的预加载最常用的方式是使用js中的image对象,通过image对象设置src属性,来实现图片的预加载。
总:
这两种方式都是提高网页性能的方式,两者主0 要区别是一个要提前加载好,一个是延迟加载。懒加载对服务前端有一定的缓解压力的作用,预加载则会增加服务端压力。
39 设计模式
设计模式可以分为三大类:
-
结构型模式:通过识别系统中组件间的简单关系来简化系统色设计
-
创建型模式:处理对象的创建,根据实际情况使用合适的方式创建对象
-
行为型模式:用于识别对象之间常见的交互模式并加以实现,如此增加了这些交互的灵活性。
39.1 工厂模式
说明:你可以想象一个场景,假设有一份很复杂的代码需要用户去调用,但是用户并不关心这些复杂的代码,只需要你提供一个接口去调用,用户只负责传递需要的参数,至于这个参数怎么使用,内部逻辑不用关心,只需要你最后返回一个实例,这个构造过程就是工厂。
工厂起到的作用就是隐藏了创建实例的复杂度,只需要一个接口,简单清晰。
现实生活中的工厂按照既定的程序制造产品,随着生产原料和流程不同生产出来的产品也会有区别。应用到软件工厂的领域,工厂可以看成是一个制造其他对象的对象,制造出来的对象也会随着传入共产对象的参数的不同而有所区别
那么,什么时候适合使用共产模式而不是直接new一个对象呢?当构造函数过多不便管理,且需要创建的对象之间存在某些关联(有同一个父类,实现同一个接口)时,不妨使用工厂模式,工厂模式提供一种集中化,统一化的方式,避免了分散创建对象导致的代码重复、灵活性差的问题。
举例如下:(构造一个简单的汽车工厂来生产汽车)
//汽车构造函数
function Car1(color) {
this.color = color
this.brand = ‘Car1’
}
//汽车构造函数
function Car2(color) {
this.color = color;
this.brand = ‘Car2’
}
//汽车构造函数
function Car3(color) {
this.color = color;
this.brand = ‘Car3’
}
//汽车的品牌
const BRANDS = {
car1: 1,
car2: 2,
car3: 3
}
//汽车工厂
function createCar() {
this.create = function (brand, color) {
switch (brand) {
case BRANDS.car1:
return new Car1(color);
case BRANDS.car2:
return new Car2(color);
case BRANDS.car3:
return new Car3(color);
default:
break;
}
}
}
//测试
const carFactory = new createCar();
const cars = [];
cars.push(carFactory.create(BRANDS.car1, ‘red’))
cars.push(carFactory.create(BRANDS.car2, ‘greed’))
cars.push(carFactory.create(BRANDS.car3, ‘pink’))
function say() {
console.log(Hi , I am ${this.color} and ${this.brand} car
)
}
for (const car of cars) {
say.call(car)
}
结果如下
使用工厂模式后,不再需要重复引入一个个构造函数,只需要引入工厂对象便可以创建各类对象
39.2 单例模式
单例模式的核心就是保证全局只有一个对象可以访问,Class的实例个数最多为1,一般全局缓存、全局状态管理等待这些只需要一个对象,就可以使用单例模式。 即我们只需要用一个变量确保实例只创建一次就可以,以下为其实例:
class Singleton {
constructor() {
}
}
Singleton.getInstance = (function () {
let instance;
return function () {
//这里使用的闭包,使用闭包保存局部作用域中的单例对象并返回
if (!instance) {
instance = new Singleton();
}
return instance;
}
})()
let s1 = new Singleton.getInstance();
let s2 = new Singleton.getInstance();
console.log(s1 === s2) //true
设计思路:即当instance为空时,则new创建新对象,若不为空时返回原来的instance对象,因此使得每次都是同一个对象
39.3 代理模式
代理是为了控制对对象的访问,不让外部直接访问到对象,也有很多代理的场景。比如事件代理就用到了代理模式。
- 1
- 2
- 3
- 4
- 5
因为存在太多的li,不可能内个都去绑定事件,这时可以通过给父节点绑定一个事件,让父节点作为代理去拿到真实点击的节点。
39.4 发布-订阅者模式
发布-订阅者模式也叫作观察者模式。通过一对一或者一对多的依赖关系,当对象发生改变时,订阅方也会收到通知。
-
在现实生活中如商品缺货时点击有货通知的按钮
-
在实际代码中如我们点击一个按钮触发了点击事件就是使用了观察者模式
let ul = document.querySelector(‘#ul’);
ul.addEventListener(‘click’, function (event) {
console.log(event.target)
})
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
最后:
总结来说,面试成功=基础知识+项目经验+表达技巧+运气。我们无法控制运气,但是我们可以在别的地方花更多时间,每个环节都提前做好准备。
面试一方面是为了找到工作,升职加薪,另一方面也是对于自我能力的考察。能够面试成功不仅仅是来自面试前的临时抱佛脚,更重要的是在平时学习和工作中不断积累和坚持,把每个知识点、每一次项目开发、每次遇到的难点知识,做好积累,实践和总结。
为、OPPO等大厂,18年进入阿里一直到现在。**
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-84RSXgU3-1712547219510)]
[外链图片转存中…(img-6qk1UErF-1712547219511)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
[外链图片转存中…(img-7HLpf94P-1712547219511)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
最后:
总结来说,面试成功=基础知识+项目经验+表达技巧+运气。我们无法控制运气,但是我们可以在别的地方花更多时间,每个环节都提前做好准备。
面试一方面是为了找到工作,升职加薪,另一方面也是对于自我能力的考察。能够面试成功不仅仅是来自面试前的临时抱佛脚,更重要的是在平时学习和工作中不断积累和坚持,把每个知识点、每一次项目开发、每次遇到的难点知识,做好积累,实践和总结。
-