react的setState的原理?setState如何更新的?
- 执行
setState
,内部执行enqueueSetState
将当前传入的对象或数组推入队列 2.enqueueSetState
执行之前会判断队列是否为空,为空代表第一次往队列添加。这时设置一个微任务(执行清空队列flush
) - 然后继续执行所有同步代码(其中可能有多个
setState
,因此循环第一第二步) - 所有同步代码执行完毕,将下一个微任务推入队列
flush
- 然后
flush
内部会合并所有队列中的state
对象,然后更新对应组件。
-
为什么
setState
传入函数就可以同步? 因为Object.assign
无法合并函数,函数会先执行,后合并,所以所有函数内部都可以获取到上个state
的值 -
为什么直接修改
this.state
无效 因为setState
本质是通过一个队列机制来实现state
更新的。执行setState
时,会将需要更新的state
合并后放入状态队列,而不会立刻更新state
,队列机制可以批量更新state
。如果不通过setState
而直接修改this.state
,那么这个state
不会放入状态队列中,下次调用setState时对状态队列进行合并时,会忽略之前直接被修改的state
,这样就无法合并state
,而已也没有直接更新state
tcp和udp的区别
tcp | udp |
---|---|
需要三次握手建立连接 | 不需要建立连接 |
可靠,丢包会重传 | 不可靠,丢包不会重传 |
有序 | 无序 |
无界,通过字节流传输 | 有界,每个包都是单独的 |
tcp有流量控制(拥塞控制) | 没有流量控制 |
传输速度慢 | 传输速度快 |
包头大,20字节 | 包头小,8字节 |
react从jsx到真实dom的过程
- 使用React.createElement或者jsx编写react组件,实际上所有的jsx代码最后都会转换成React.createElement(...),Babel帮助我们完成了这个转换的过程
- createElemnt函数对key、self、ref等特殊的props进行处理,并获取defaultProps对默认props进行赋值,并且对传入的孩子节点进行处理,最终构造成一个虚拟DOM对象
- ReactDOM.render将生成好的虚拟DOM渲染到指定容器上,其中采用了批处理、事物等机制并且对特点浏览器进行了性能优化,进行diff算法,为fiber打上tag,最终转换成真实DOM
new做了什么
- 在内存中创建一个新对象
- 在这个新对象内部的[[Prototype]]特性被赋值为构造函数的prototype属性
- 构造函数内部的this被赋值为这个新对象(即this指向新对象)
- 执行构造函数内部的代码(给新对象添加属性)
- 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象
XSS攻击和CSRF攻击
XSS攻击(Cross Site Scripting,跨站脚本攻击):是指利用攻击者利用站点的漏洞,在表单提交时,在表单内容中加入一些恶意脚本,当其他正常用户浏览页面,而页面中刚好出现攻击者的恶意脚本时,脚本被执行,从而使得页面遭到破坏,或者用户信息被窃取。
注入方法:
- 在HTML中内嵌的文本中,恶意内容以script标签形成注入
- 在内联的
javascript
中,拼接的数据突破了原本的限制(字符串、变量、方法名等) - 在标签属性内,恶意内容包含引号,从而突破属性值的限制,注入其他属性或者标签
- 在标签的
href、src
等属性中,包含javascript:
伪协议等可执行代码 - 在
onload、onerror、onclick
等事件中,注入不受控制代码 - 在style属性和标签中,包含类似
background-image:url("javascript:...");
的代码(新版本浏览器已经可以防范) - 在style属性和标签中,包含类似
expression(...)
的css表达式代码(新版本浏览器已经可以防范)
xss攻击的分类
- 存储型XSS:存储型xss的攻击步骤-1)攻击者将恶意代码提交到目标网站的数据库中;2)用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在HTML中返回给浏览器;3)用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行;4)恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
存储行xss(又被称为持久性xss)攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。它是最危险的一种跨站脚本,相比反射型xss和dom型xss具有更高的隐蔽性,所以危害更大,因为他不需要用户手动触发。任何允许用户存储数据的web程序都可能存在存储型xss漏洞,当攻击者提交一段xss代码后,被服务器端接收并存储,当所有浏览者访问某个页面时都会被xss
- 反射型XSS:反射型xss的攻击步骤-1)攻击者构造出特殊的URL,其中包含恶意代码;2)用户打开带有恶意代码的URL时,网站服务端将恶意代码从URL中取出,拼接在HTML中返回给浏览器。3)用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行;4)恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
反射型xss跟存储型xss的区别是:存储型xss的恶意代码存在数据库里,反射型xss的恶意代码存在URL里。反射型XSS(也被称为非持久性XSS)漏洞常见于通过URL传递参数的功能,如网站搜索、跳转等。由于需要用户主动打开恶意的URL才能生效,攻击者往往会结合多种手段诱导用户点击。POST的内容也可以触发反射型XSS,只不过其触发条件比较苛刻(需要构造表单提交页面,并引导用户点击),所以非常少见
- DOM型XSS:DOM型XSS的攻击步骤-1)攻击者构造出特殊的URL,其中包含恶意代码。2)用户打开带有恶意代码的URL;3)用户浏览器接收到响应后解析执行,前端js取出URL中的恶意代码并执行。4)恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
DOM型XSS跟前两种的区别是:DOM型XSS中,取出和执行恶意代码由浏览器端完成,属于前端js自身的安全漏洞,而其他两种都属于服务端的安全漏洞
要防范XSS攻击,需要在服务器端过滤脚本代码,将一些危险的元素和属性去掉或对元素进行HTML实体编码
常用防范方法
- httpOnly:在cookie中设置httpOnly属性后,js脚本将无法读取到cookie信息
- 输入过滤:一般是用于对输入格式的检查,例如:油箱、电话号码、用户名、密码等,按照规定的格式输入。不仅仅是前端负责,后端也要做相同的过滤检查。因为攻击者完全可以绕过正常的输入流程,直接利用相关接口向服务器发送设置。
- 转义HTML:如果拼接HTML是必要的,就需要对引号,尖括号、斜杠进行转义,但这还不是很完善,相对HTML模板各处插入点进行充分的转移,就需要采用合适的转义库。
- 白名单:对于显示富文本来说,不能通过上面的方法来转义所有字符,因为这样会把需要的格式也过滤掉,这种情况通常采用白名单过滤的办法,当然也可以通过黑名单过滤,但是考虑到需要过滤的标签和标签属性实在太多,更加推荐使用白名单的方式。
CSRF(Cross-site request forgery)即跨站请求伪造,也被称为one-click-attack或者session riding,通常缩写为CSRF或者XSRF,是一种挟制用户在当前已登录的web应用程序执行非本意的操作的攻击方法。如:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。
CSRF的攻击过程:
- 用户C浏览并登录信任网站A
- 验证通过,在用户C处产生网站A的cookie
- 在用户C没有登出网站A的情况下,访问危险网站B
- 危险网站B要求访问网站A,发出一个请求request
- 根据危险网站B在4.的请求,浏览器带着2.的cookie访问A
- 网站A不知道5.发出的请求是危险网站B发出的还是用户C发出的,由于浏览器会自动带上用户C的cookie,所以A会根据用户的权限处理5.的请求,这样危险网站B就达到了模拟用户操作的目的
CSRF攻击的特点:
- 攻击一般发起在第三方网站,而不是被攻击的网站。
- 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作,而不是直接窃取数据
- 整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”
- 跨站请求可以用各种方式:图片URL、超链接、CORS、FORM提交等。部分请求方式可以直接嵌入第三方论坛、文章中,难以进行追踪。
CSRF攻击通常是跨域的,因为外域通常更容易被攻击者掌握。但是如果本域下有容易被利用的功能,比如可以发图和链接的论坛和评论区,攻击可以直接在本域下进行,而且这种攻击更加危险。
CSRF和XSS的区别
- 通常来说CSRF是由XSS实现的,CSRF时常被称为XSRF(CSRF实现的方式还可以是直接通过命令行发起请求等)
- 本质上讲,XSS是代码注入问题,CSRF是HTTP问题。XSS是内容没有过滤导致浏览器将攻击者的输入当代码执行。CSRF则是因为浏览器在发送HTTP请求时自动带上cookie,而一般网站的session都存在cookie里面(token验证可以避免)
CSRF的防御方式:
- 验证码:强制用户必须与应用进行交互,才能完成最终请求。此种方式能很好的遏制csrf,但是用户体验比较差。
- Referer check:请求来源限制,此种方法成本最低,但是并不能保证100%有效,因为服务器并不是什么时候都能获取到Referer,而且低版本的浏览器存在伪造Referer的风险。
- token:token验证的CSRF防御机制是公认最合适的方案,但是如果网站同时存在XSS漏洞的时候,这个方法也是空谈。
- 双重cookie
- samesite cookie
- 具体方法看前端安全系列之二:如何防止CSRF攻击? - 掘金 (juejin.cn)
react的不可变性
在React中,不可变性指数据一旦被创建,就不能被修改。React推崇使用不可变数据的原则,这意味着在更新数据时,应该创建新的数据对象而不是直接修改现有的数据。
以下是理解React中不可变性原则的几个关键点:
- 数据一旦被创建就不能被修改:在React中,组件的状态(state)和属性(props)应该被视为不可变的。一旦创建了状态或者属性对象,就不应该直接修改它们的值。这样可以确保组件的数据在更新时是不可变的,从而避免意外的数据改变和副作用。
- 创建新的数据对象:当需要更新状态或属性时,应该创建新的数据对象。这可以通过使用对象展开运算符、数组的concat、slice等方法,或者使用不可变数据库(如Immutable.js、Immer等)来创建新的数据副本
- 比较数据变化:React使用Virtual DOM来比较前后两个状态树的差异,并仅更新需要更新的部分。同构使用不可变数据,React可以更高效的进行比较,因为它可以简单的比较对象引用是否相等,而不必逐个比较对象的属性。
- 性能优化:使用不可变数据可以带来性能上的优势。由于React可以更轻松的比较前后状态的差异,可以减少不必要的重新渲染和组件更新,提高应用的性能和响应性。
不可变性的原则在React中有以下好处:
- 简单数据变更追踪:由于数据不可变,可以更轻松的追踪数据的变化。这样可以更好的理解代码的行为和数据的流动
- 避免副作用:可变数据容易引发副作用和难以追踪的bug。通过使用不可变数据,可以避免许多与副作用相关的问题。
- 方便的历史记录和回滚:不可变数据使得记录和回滚应用状态的历史变得更容易。可以在不改变原始数据的情况下,创建和保存不同时间点的数据快照。
Promise的原理
ajax的原理和步骤
ajax的原理简单来说就是通过XMLHttpRequest对象来向服务器发送异步请求,从服务器获得数据,然后用js来操作DOM而更新页面。
ajax的步骤为:
- 创建ajax的核心对象XMLHttpRequest对象
- 通过XMLHttpRequest对象的open方法与服务器建立连接
- 构建请求所需的数据内容,并通过XMLHttpRequest对象的send方法发送给服务器端
- 通过XMLHttpRequest对象提供的onreadystatechange事件来监听服务端与客户端的通信状态
- 接收并处理服务端向客户端响应的数据结果
- 将处理结果更新到HTML页面中
const request = new XMLHttpRequest()
request.open('POST', 'http://xxx')
request.send()
request.onreadystatechange = function(e) {
if(request.readystate === 4 && request.status === 200) {
document.getElementById('.root').innnerHTML = request.responseText
}
}
readyState:
- 0: 请求未初始化
- 1: 服务器连接已建立,已调用open
- 2: send已被调用,并且头部和状态已经可以获得
- 3: 下载中;responseText属性已经获得部分数据
- 4: 下载已完成;responseText属性已经获得全部数据
position: fixed
元素会被移出正常文档流,并不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在每页的固定位置。fiexd
属性会创建新的层叠上下文。当元素祖先的transform、perspective、filter
或backdrop-filter
属性非none
时,容器由视口改为该祖先
css优化
- 压缩和合并css文件
- 减少http请求
- 使用精简的选择器
- 优化字体和图片,比如css精灵图
- 使用现代布局技术,比如flexbox和grid布局
- 使用浏览器缓存
- 使用gpu渲染,比如transformer、will-change等
- 删除不必要的样式
- 将css拆分为独立模块,按需加载
- 预加载重要资源,比如preload
- 优化渲染阻塞