区别:
1)虚拟dom不会进行重绘和回流,而真实dom会频繁重排与重绘
2)虚拟dom的总损耗是”虚拟dom的增删改+真实dom的差异增删改+重排“;
真实dom的消耗是”真实dom全部增删改+重排“
真实dom:
优点:直接操作html,易用
缺点:解析速度慢,效率低,内存占用良高,性能差,频繁操作真实dom
虚拟dom
优点:减少真实dom的频繁更新,减少重绘回流,占用内存少,跨平台
缺点:页面首次渲染时,由于多一层虚拟dom的计算,速度相对较慢
React 利用状态队列机制实现了 setState 的“异步”更新,避免频繁的重复更新 state。
首先将新的 state 合并到状态更新队列中,然后根据更新队列和 shouldComponentUpdate
的状态来判断是否需要更新组件
React是在document处监听了所有的事件,当事件发生并且冒泡到document处的时候,
react将事件内容封装并交到真正的处理函数运行,减少内存消耗,合成事件磨平了浏览器之间的兼容问题,
赋予了跨浏览器开发的能力,对于原生事件监听,浏览器会给监听器创建一个事件对象,事件回调结束后,
就会销毁事件对象上的属性,从而便于下次复用事件对象
受控组件:指的是这个值受到setState()的影响,当页面刷新时,它会根据是值是否变化进行刷新
非受控组件:指的是不受setState()的影响,像input框中的值,只取决于本身DOM节点的值,
从新属性是值不发生变化
Fiber 可以理解为一个执行单元,每次执行完一个执行单元,react 就会检查现在还剩多少时间,
如果没有时间则将控制权让出去。
首先 React 向浏览器请求调度,浏览器在一帧中如果还有空闲时间,会去判断是否存在待执行任务,
不存在就直接将控制权交给浏览器,如果存在就会执行对应的任务,执行完成后会判断是否还有时间,
有时间且有待执行任务则会继续执行下一个任务,否则就会将控制权交给浏览器。
1)Diff算法是虚拟DOM的一个必然结果,它是通过新旧DOM的对比,将在不更新页面的情况下,
将需要内容局部更新
2)Diff算法遵循深度优先,同层比较的原则
3)可以使用key值,可以更加准确的找到DOM节点
react中diff算法主要遵循三个层级的策略:
tree层级
conponent 层级
element 层级
tree层不会做任何修改,如果有不一样,直接删除创建
component层从父级往子集查找,如果发现不一致,直接删除创建
element层有key值做比较,如果发现key值可以复用的话,就会将位置进行移动,如果没有,则执行删除创建
div {
background: red;
clip-path: polygon(0 0, 100% 0, 0 100%, 0 0);
}
缓存:缓存是指浏览器(客户端)在本地磁盘中队访问过的资源保存的副本文件。
强缓存: 强缓存是根据返回头中的 Expires 或者 Cache-Control 两个字段来控制的,
都是表示资源的缓存有效时间。
协商缓存: 协商缓存是由服务器来确定缓存资源是否可用。 主要涉及到两对属性字段,都是成对出现的,
即第一次请求的响应头带上某个字, Last-Modified 或者 Etag
React render方法的原理,在什么时候会触发?
原理:
在类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件
render函数中的jsx语句会被编译成我们熟悉的js代码,在render过程中,react将新调用的render函
数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比
较,更新dom树
触发时机:
类组件调用 setState 修改状态
函数组件通过useState hook修改状态
一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行
render方法,一旦父组件发生渲染,子组件也会渲染
1)避免使用内联函数
2)使用react fragement 避免额外标记
3)immutable,减少渲染的次数,为了避免重复渲染,会在shouldComponentUpdate()中做对
比,当返回true,执行render方法。immutable通过is方法完成对比
4)懒加载组件
5)事件绑定方式(在constructor中使用bind绑定性能更高)
6)服务端渲染
7)组件拆分,合理使用hooks
Less-loader:处理less
Sass-loader:处理sass
Style-loader:将css添加到dom的内联样式style的标签里
Postcss-loader:用postcss来处理css
file-loader: 分发文件到output目录并返回相对路径
html-minify-loader: 压缩HTML
Babel-loader:用babel来转换ES6文件
JS代码压缩
CSS代码压缩
Html文件代码压缩
文件大小压缩
图片压缩
Tree Shaking
代码分离
内联 chunk
由于疏忽或错误造成程序未能释放不在使用的内存,如果不及时释放,会造成内存占比越来越高,
对项目中的内存会造成很大的影响
常见的内存泄漏情况?
1.意外的全局变量
2.意外的全局变量可能由 this 创建
3.定时器也常会造成内存泄露
4.闭包函数
5.没有清理对DOM元素的引用同样造成内存泄露
1.意外的全局变量
2.意外的全局变量可能由 this 创建
3.定时器也常会造成内存泄露
4.闭包函数
5.没有清理对DOM元素的引用同样造成内存泄露
react是一个前端js框架,高效灵活,有着声明式设计,
使用简单,组件式开发,可以提高代码的复用率,
单向的数据绑定,更加安全
特性:
单项数据流
JSX语法
虚拟DOM
声明式编程
Component
diff算法可以看作是一种对比算法,对比的对象是 新旧虚拟Dom。
diff算法可以找到新旧虚拟Dom之间的差异,但 diff算法中其实并不是只有对比 虚拟Dom,
还有根据对比后的结果更新 真实Dom。
合理利用key可以有效减少真实Dom的变动,从而减少页面重绘和回流的频率,进而提高页面更新的效率。
挂载卸载阶段
constructor,完成了React数据的初始化;
componentWillMount,组件初始化数据后,未渲染DOM前;
componentDidMount,组件第一次渲染完成,dom节点已经生成;
componentWillUnmount,组件的卸载和数据的销毁。
更新过程阶段
componentWillReceiveProps (nextProps),父组件改变后的props需要重新渲染组件时;
shouldComponentUpdate(nextProps,nextState),主要用于性能优化(部分更新),
因为react父组件的重新渲染会导致其所有子组件的重新渲染,这个时候不需要所有子组件都跟着重新渲染,
然后return false就可以阻止组件的更新;
componentWillUpdate (nextProps,nextState),shouldComponentUpdate返回true后,
组件进入重新渲染的流程;
componentDidUpdate(prevProps,prevState),组件更新完毕后触发;
render(),渲染时触发
1)虚拟DOM本质上是一个Object类型的对象
2)虚拟DOM比较轻,真实DOM比较重,虚拟DOM是React内部使用,虚拟DOM不需要真实DOM上那么多的属性
3)虚拟DOM最终回被React渲染到页面上
hook是react新增的一个特性,
hook主要解决了函数组件没有生命周期没有状态,
一些自身逻辑的问题,还可以提高代码的复用率,
常用的Hook有useState(),useCallBack(),useEffect(),useReducer()
父组件向子组件传递:父组件在调用子组件的时候,在子组件的标签内传递参数,
子组件通过props属性就能接收父组件传递过来的参数
子组件向父组件传递:父组件向子组件传一个函数,然后通过这个函数的回调,拿到子组件穿过来的值
兄弟组件之间的通信:父组件作为中间层来实现数据的互通,通过使用父组件传递
父组件向后代组件传递:使用context提供了组件之间通讯的一种方式,可以共享数据
非关系组件传递:将数据进行一个全局资源管理实现数据互通
Connect组件有两个参数,第一个是mapStateToProps,这个函数允许将store中的数据作为props绑定到组件上,
第二个参数是mapDispatchToProps,由于更改数据必须要触发action,主要功能就是将action绑定到组件上,
procider它就是一个容器组件,会嵌套的内容作为子组件渲染出来,
它还会把外界传给它的props.store放到context中
Jsx是一种语法规范,
在创建虚拟dom的时候不能使用引号,
标签必须是闭合的,
如果混入js语法就要使用{},
内联样式使用style={{}},
首字母要大写,
class类名写成className
中间件在计算机中,是介于应用系统和系统软件之间的一类软件,它使用系统软件所提供的基础服务(功能),
衔接网络上应用系统的各个部分或不同的应用,能够达到资源共享、功能共享的目的
常见的中间件:
redux-thunk:用于异步操作
redux-logger:用于日志记录
redux中间件就是辅助redux不能完成的功能
applayMiddleWare()用它包裹将要使用的插件
commonjs规范加载模块是同步的,只有加载完成才能执行后面的操作
AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块。
CMD推崇就近依赖,只有在用到某个模块的时候再去require。
对于依赖的模块AMD是提前执行,CMD是延迟执行。不过RequireJS从2.0开始,也改成可以延迟执行。
AMD推崇依赖前置,AMD的api默认是一个当多个用,CMD严格的区分
第一部分为主版本号,变化了表示有了一个不兼容上个版本的大更改
第二部分为次版本号,变化了表示增加的新的功能,并且可以向后兼容
第三部分为修订版本号,表示有bug修复,并且可以向后兼容
第四部分为日期版本号加希腊字母版本号
JSX在被编译后,会变成一个针对 React.createElement 的调用。
ceateElement的大致流程为:
二次处理key、ref、self、source四个属性值;
遍历config,筛选可以提到props中的属性;
将children中的子元素推入childArray数组;
格式化defaultProps
将以上数据作为入参,发起ReactElement的调用,最终由ReactElement返回虚拟Dom对象
最终将虚拟Dom传入ReactDom.render函数中,将其转变为真实Dom
reduxjs/toolkit:是redux官方强烈推荐,开箱即用的一个高效的redux开发工具集,
旨在成为标准的redux逻辑开发模式,使用redux Tookit可以进行代码的优化,使其更可维护
React-redux:是官方推出redux绑定库,react-redux将所有的组件分成两大类UI组件和容器组件,
其中所有容器组件包裹着ui组件构成父子关系,容器组件会给UI组件传递redux中保存对的
状态和操作状态的方法
区别:
1、reduxjs/tookit相对于react-redux来说比较方便,集成了redux-devtools-extension,
不需要额外的配置,非常方便
2、reduxjs/tookit集成immutable-js的功能,不需要安装配置使用,提升了开发效率
3、reduxjs/tookit集成了redux-thunk的功能
4、reduxjs/tookit将types、actions、reducers放在一起组成了全新的slices,简化了我们的使用
原理:在类组件中render函数指的就是render方法,而在函数组件中指的就是整个函数组件,
render函数中的jsx语法会被编译成我们熟悉的js代码,在render过程中,
react将新调用的render函数返回的树与旧版本的树进行比较,这一步是决定如何更新dom的必要步骤,
然后进行diff比较,更新dom树
触发时机:类组件调用setState修改状态,
函数组件通过useState hook修改状态,
一旦执行了setState就会执行render方法,一旦父组件发生渲染,子组件也会渲染
避免使用内联函数
使用react避免额外标记
Immutable减少渲染次数,避免重复渲染
懒加载组件
事件绑定方式
服务端渲染
组件拆分,合理使用hooks
防抖
const debounce = (func, wait = 50) => {
let timer = 0
return function(…args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, args)
}, wait)
}
}
节流
export const throttle = function (fn, wait = 500) {
let flg = true
return function () {
if (!flg) return;
flg = false
setTimeout(() => {
fn.apply(this, arguments)
flg = true
}, wait);
}
}
Koa的洋葱模型是以next()函数为分割点,先由外到内执行Request的逻辑,
然后再由内到外执行Response的逻辑,这里的request的逻辑,我们可以理解为是next之前的内容,
response的逻辑是next函数之后的内容,也可以说每一个中间件都有两次处理时机。
洋葱模型的核心原理主要是借助compose方法。
Js代码压缩
Css代码压缩
文件大小压缩
代码分离
HTML代码压缩
内联chunk
webSocket是一种网络传输协议,位于OSI模型的应用层,可在单个tcp连接上进行全双工通信,
能更好的节省服务器资源和带宽并达到实时通讯,客户端和服务器只需要完成一次握手,
两者之间就可以创建持久性的链接,并进行双向数据传输,较少的控制开销,更强的实时性,
保持创连接状态,更好的二进制支持,还有更好的压缩效果
shouldComponentUpdate():用于控制组件重新渲染的流程在这return false可以阻止组件的更新
Bind:只调用一次,指令第一次绑定到元素时调用,在这里可以记性一次性的初始化设置
Inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)
Update:所在组件的VNode更新时调用,但是可能发生在其VNode更新之前。指令的值可能发生了改变,
也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
componentUpdate:指令所在组件的VNode及其子VNode全部更新后调用
Unbind:只调用一次,指令与元素解绑时调用
应用场景:表单防止重复提交、图片懒加载、一键Copy的功能
connect是一个高阶函数,首先传入mapStateToProps、mapDispatchToProps,
然后返回一个生产Component的函数(wrapWithConnect),然后再将真正的Component作为参数传入wrapWithConnect,
这样就生产出一个经过包裹的Connect组件,
该组件具有如下特点:
通过props.store获取祖先Component的store
props包括stateProps、dispatchProps、parentProps,合并在一起得到nextState,作为props传给真正的Component
componentDidMount时,添加事件this.store.subscribe(this.handleChange),实现页面交互
shouldComponentUpdate时判断是否有避免进行渲染,提升页面性能,并得到nextState
componentWillUnmount时移除注册的事件this.handleChange
断点续传指的是在下载或上传时,将下载或上传任务人为的分为几个部分,每个部分采用一个线程进行上传或下载,
如果碰到网络故障,可以从已经上传或下载的部分继续进行文件的上传或者下载,而没必要从头开始上传下载。
用户可以节省时间,提高速度
一般实现方式有两种:服务器端返回,告知从哪开始;浏览器端自行处理
上传过程中将文件在服务器写为临时文件,等全部写完了(文件上传完)将此临时文件重命名为正式文件
如果中途上传中断过,下次上传的时候根据当前临时文件大小,作为客户端读取文件的偏移量,
从此位置开始继续读取文件数据块,上传到服务器从此偏移量继续写入文件即可
上拉加载的本质是页面触底,或者快要触底时的动作,scrollTop:滚动视窗的高度距离window顶部的距离,
他会随着往上滚动而不断的增加,初始值是0,他是一个变化的值
ClientHeight:他是一个定值,表示屏幕可视区域的高度
ScrollHeight:页面不能滚动时是不存在的,body长度超过window时才会出现,所表示body所有元素的长度
实现上拉加载:
Let clientHight = document.documentElement.clientHight
Let ScrollHeight= document.body.ScrollHeight
Let scrollTop= document.documentElement.scrollTop
Let distance=50;//距离视窗还有50时开始触发
If(scrollTop+clientHight)>=(ScrollHeight-distance){
Console.log(“刷新数据”)
}
下拉刷新的本质就是当页面处于顶部时用户下拉页面时触发的动作
实现下拉刷新:监听touchstart时间,记录其初始位置的值,e.touches[0].pageY
监听原生touchmove事件,记录并计算当前滑动的位置值与初始位置值的差值,大于0表示向下拉动,
并借助css3的translateY属性使元素跟随手势向下滑动对应的差值,同时也应设置一个允许滑动的最大值,
监听原生touchend事件,若此时元素滑动达到最大值,则触发callback,同时将translateY设置为0元素回到初始值
设备像素:又称为物理像素,指设备只能控制显示的最小物理单位,不一定是一个小正方形区块,
也没有标准的宽高,只是用于显示丰富色彩的一个“点”而已
Css像素:适用于web编程,在css中以px为后缀,是一个长度单位
设备独立像素:与设备无关的逻辑像素,代表可以通过程序控制使用的虚拟像素,是一个总体概念,
包括了css像素
Dpr:设备像素比,代表设备独立像素的转换关系,在javascript中可以通过window.devicePixelRatio获取
Ppi:每英寸像素,表示每英寸所包含的像素点数目,更确切的说法应该是像素密度,
数值越高说明屏幕能以更高密度显示图像
BFC是块级格式化上下文,他是页面中的一块渲染区域,并且有一套属于自己的渲染规则
内部的盒子会在垂直方向上一个接一个的放置
对于同一个BFC的两个相邻的盒子的margin会发生重叠,与方向无关
每个元素的左外边距与包含块的左边界相接触,即使浮动元素也是如此
BFC的区域不会与float的元素区域重叠
计算BFC的高度时,浮动子元素也参与计算
BFC目的是形成一个相对于外界完全独立的空间,让内部的元素不会影响到外部的元素
三次挥手其实就是指建立一个TCP连接时,需要客户端和服务器端总共发送三个包,
主要作用就是为了确认双方的接收能力和发送能力是否正常,指定自己的初始化序号为后面的可靠性传送做准备
TCP终止一个连接,需要经过次握手
服务器端在收到客户端断开连接fin报文后,并不会立即关闭连接,而是先发送一个ACK的包,
先告诉客户端收到关闭连接的请求,只有当服务器的所有报文发送完毕后才发送FIN报文断开连接,
因此需要四次挥手
新出来的两个钩子函数是:getDerivedStateFromProps和getSnapshotBeforeUpdate
componentWillmount()在ssr中这个方法将会被重复触发很多遍同时在这里如果绑定事件,
将不能解绑,就会导致内存泄漏,变得不够安全高效
ComponentWillReceiveProps()外部组件多次频繁的更新传入多次不同的props,会导致不必要的异步请求
ComponentWillUpdate()更新前记录Dom状态,可能会做一些处理,与componentDidUpdate()
相隔时间如果过长,就会导致状态不可信
react新的生命周期中getDerivedStateFromProps函数替换掉了componentWillmount()和
ComponentWillReceiveProps()生命周期函数,用getSnapshotBeforeUpdate函数替换
componentWillUpdate方法避免了和componentDidUpdate函数中获取的数据不一致的问题
额外标签法:在需要清除浮动的元素前面加上空div并设置clear为both
浮动引起的父元素高度塌陷时:设置父元素overflow属性为hidden或auto
After:伪元素清除浮动
(1)使用React.createElement或者JSX编写React组件,实际上所有jsx代码最后都会转换成
React.createElement(),Babel帮助我们完成了这个转换的过程。
(2)createElement函数对key和ref等特殊的props进行处理,并获取defaultProps对默认
props进行赋值,并且对传入的孩子节点进行处理,最终构造成一个虚拟DOM对象
(3)ReactDOM.render将生成好的虚拟dom渲染到指定容器上,其中采用了批处理、
事务等机制并且对特定浏览器进行了性能优化,最终转化为真实DOM
在类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件render函数中
的jsx语句会被编译成我们熟悉的js代码,在render过程中,react将新调用的render函数返回的树与
旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比较,更新dom树
触发时机:
类组件调用 setState 修改状态
函数组件通过useState hook修改状态
一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行
render方法,一旦父组件发生渲染,子组件也会渲染
避免使用内联函数;
事件的绑定方式,
懒加载组件;
服务器端渲染;
使用react fragement 避免额外标记
组件拆分,合理使用hooks;
Rebase可以使PR整洁,干净且相关,而不会产生嘈杂的提交
Merge具有更高的可追溯性,而Rebase则更整洁且易于审核
区别:
这两种方法之间的最大区别在于,合并保留了作品的完整历史记录,包括按时间顺序排列,
而Rebase使提交变得整洁,仅与分支上的作品相关
合并具有较高的可追溯性
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。 Symbol函数前不能使用new命令,否则会报错。
这是因为生成的Symbol是一个原始类型的值,不是对象 Symbol函数可以接受一个字符串作为参数,
表示对Symbol实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
setState是异步还是同步:
合成事件中是异步
钩子函数中的是异步
原生事件中是同步
setTimeout中是同步
1)代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程
(Reconciliation)。
2)经过调和过程, React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面;
3)在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染;
4)在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,
而不是全部重新渲染。
props是一个从外部传进组件的参数,由于React具有单向数据流的特性,所以他的主要作用是从父组件向子组件中传递数据,它是不可改变的,
如果想要改变它,只能通过外部组件传入新的props来重新渲染子组件,否则子组件的props和展示形式不会改变,props除了可以传字符串,
数字,还可以传递对象,数组甚至是回调函数
state主要作用是用于组件保存,控制及修改自己的状态,它只能在constructor中初始化,state是可以被改变的,state放改动的一些属性,
比如点击选中,再点击取消,类似这种属性就放入带state中,注意:没有state的叫做无状态组件,多用props少用state,多写无状态组件,
注意:修改state的值时,必须通过调用setState方法,当我们调用this.setState方法时,React会更新组件的数据状态,
并且重新调用render方法
render方法在类组件抵用setState修改状态时;
函数组件通过useState hook或者通过useState修改状态时;
当我们的数据发生改变render方法就会触发
shouldComponentUpdate 函数是 React 中的一个生命周期函数,
用于在更新组件前检查数据是否有变化,从而决定是否重新渲染组件
shouldComponentUpdate 函数的作用:
(1)提升组件性能:当组件在接收到新的 props 和 state 时,可以通过shouldComponentUpdate
判断是否需要重新渲染,减少不必要的渲染
(2)允许控制: React通过此函数允许开发者控制组件是否重新渲染,能够提高开发效率,实施预期的操作。
虚拟dom本质上是js对象,是真实dom的抽象,状态变更时记录新旧dom树的差异,
最后把差异更新到真实dom中去,react虚拟dom是在浏览器端用js实现了一套dom接口,
基于react进行开发时所有的dom构造都是通过虚拟dom进行,
当数据发生变化是,react重新构建整个dom树,
然后react将当前整个dom树和上一次的dom树进行对比,得到dom结构的区别
getDerivedStateFromProps
getSnapshotBeforeUpdate
componentWillReceiveProps实际行为与命名并不相符,由于不稳定性已由getDerivedStateFromProps代替;
而componentWillUpdate同等理由被getSnapshotBeforeUpdate代替
在reactJS 中 props.children 不一定是数组,
有三种可能 :
1当前组件没有子节点数据类型就是undefined,
2有一个子节点数据类型就是object 。
3 有多个子节点的时候才会是array ,只有在多个节点的时候才可以直接调用 map方法,react资深提供了一个react.children.map()方法,
可以安全遍历子 节点对象。
父组件向子组件传递:父组件在调用子组件的时候,在子组件的标签内传递参数,
子组件通过props属性就能接收父组件传递过来的参数
子组件向父组件传递:父组件向子组件传一个函数,然后通过这个函数的回调,拿到子组件穿过来的值
兄弟组件之间的通信:父组件作为中间层来实现数据的互通,通过使用父组件传递
父组件向后代组件传递:使用context提供了组件之间通讯的一种方式,可以共享数据
非关系组件传递:将数据进行一个全局资源管理实现数据互通
Immutable,不可改变的,指一旦创建,就不能再被更改的数据
对 Immutable对象的任何修改或添加删除操作都会返回一个新的 Immutable对象
Immutable 实现的原理是 Persistent Data Structure(持久化数据结构):
用一种数据结构来保存数据
当数据被修改时,会返回一个对象,但是新的对象会尽可能的利用之前的数据结构而不会对内存造成浪费
也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变,同时为了避免 deepCopy把所有节点都复制一遍带来的性能损耗,
Immutable 使用了 Structural Sharing(结构共享)如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享
用redux执行同步的时候,都是先发起一个dispatch(actionCreator())
1.先在actionCreator()中生成一个action对象。
2.由dispatch方法将action传到reducer。
3.reducer中计算新state
4.新state保存到store中
5.因为容器组件将state作为props传给展示组件,state更新后,展示组件渲染更新的部分(因为props更新了)
app中的各部分都有纯粹而限定的职责,reducer只负责计算新state、P组件只负责渲染、C组件只负责获取update后的state和disptach
方法传递给P组件。
而异步操作,同样被归类为一种action(action可能会改变state)。所以异步操作的代码被放到action creator的返回值里,
但是dispatch方法只能接收js对象
同步action执行了dispatch函数之后,对应的reducer纯函数立即得到了执行,reducer执行完了,state立即就改变,
此时用store.getState函数,取到的是最新值
异步action原则上并没有提供异步action的处理方法,异步的action需要依赖第三方的中间件解决,dispatch了一个异步action之后,
目标store并不会立即响应,而是要看异步函数内部的逻辑,来决定state什时候响应。
redux-thunk通过对dispatch进行升级,让dispatch可以接收函数
redux-thunk可以将异步逻辑放在actionCreator里面
redux-saga和redux-thunk作用类似
store action的中间
redux-saga提供许多api put takeEvey takeLast …
redux-thunk 只是让dispatch 可以接收函数
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。 Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol
是一个原始类型的值,不是对象 Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述,主要是为了在控制台显示,
或者转为字符串时,比较容易区分。
CDN 意为内容分发网络,是基于现有网络的智能虚拟网络,分布在世界各地的边缘服务器上。
避免互联网上可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输更快更稳定
CDN 的特点
本地缓存加速
镜像服务
远程加速
带宽优化
集群抗攻击
foreach的性能要比for要高;
因为for循环要进行一个array.GetLength来获取数组最大下标。
当然只是相对的
1、如果只是读数据,选择foreach
2、如果只是写数据,选择for
3、for循环遍历的效率是低于foreach循环遍历
for循环在外部做count和在条件中做count相比较,第一种效率更高(for每次循环的时候都要去判断是否符合循环条件)
4、foreach 依赖 IEnumerable.
第一次 var a in GetList() 时 调用 GetEnumerator 返回第一个对象 并 赋给a
以后每次再执行 var a in GetList() 的时候 调用 MoveNext.直到循环结束
期间GetList()方法只执行一次
reduxjs/toolkit:是redux官方强烈推荐,开箱即用的一个高效的redux开发工具集,
旨在成为标准的redux逻辑开发模式,使用redux Tookit可以进行代码的优化,使其更可维护
React-redux:是官方推出redux绑定库,react-redux将所有的组件分成两大类UI组件和容器组件,
其中所有容器组件包裹着ui组件构成父子关系,容器组件会给UI组件传递redux中保存对的
状态和操作状态的方法
区别:
1、reduxjs/tookit相对于react-redux来说比较方便,集成了redux-devtools-extension,
不需要额外的配置,非常方便
2、reduxjs/tookit集成immutable-js的功能,不需要安装配置使用,提升了开发效率
3、reduxjs/tookit集成了redux-thunk的功能
4、reduxjs/tookit将types、actions、reducers放在一起组成了全新的slices,简化了我们的使用
原理:
在类组件中render函数指的就是render方法;而在函数组件中,指的就是整个函数组件
render函数中的jsx语句会被编译成我们熟悉的js代码,在render过程中,react将新调用的render函
数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff 比
较,更新dom树
触发时机:
类组件调用 setState 修改状态
函数组件通过useState hook修改状态
一旦执行了setState就会执行render方法,useState 会判断当前值有无发生改变确定是否执行
render方法,一旦父组件发生渲染,子组件也会渲染
(1)根据运算符优先级 ,! 的优先级是大于 == 的,所以先会执行 ![]
!可将变量转换成boolean类型,null、undefined、NaN以及空字符串(‘’)取反都为true,其余都为false。
所以 ! [] 运算后的结果就是 false
也就是 [] == ! [] 相当于 [] == false
(2)根据上面提到的规则(如果有一个操作数是布尔值,则在比较相等性之 前先将其转换为数值——false转换为0,而true转换为1),
则需要把 false 转成 0也就是 [] == ! [] 相当于 [] == false 相当于 [] == 0
(3)根据上面提到的规则(如果一个操作数是对象,另一个操作数不是,则 调用对象的valueOf()方法,
用得到的基本类型值按照前面的规则进行比较,如 果对象没有valueOf()方法,则调用 toString())
而对于空数组,[].toString() -> ‘’ 也就是 [] == 0 相当于 ‘’ == 0
(4)根据上面提到的规则(如果一个操作数是字符串,另一个操作数是数值 ,在比较相等性之前先将字符串转换为数值)
Number(‘’) -> 返回的是 0相当于 0 == 0 自然就返回 true了
一个函数和对周围状态的引用捆绑在一起,这样的组合就是闭包,闭包就是函数嵌套函数,内部函数可以访问外部函数的参数和值
在js中,每当创建一个函数,闭包就会在函数创建的同时被创建出来,作为函数内部与外部连接起来的一座桥梁
适用场景:
创建私有变量
延长变量的生命周期
倒计时,延迟调用,回调等闭包的应用,核心思想还是创建私有变量和延长变量的生命周期
一般函数的词法环境在函数返回之后就被销毁了,但是闭包会保存对创建时所在词法环境的引用,即使创建时所在的执行上下文被销毁,
但创建时的词法环境仍然存在,以达到延长变量生命周期的目的
viewport适配
借助media实现rem适配
S配合修改配合rem适配
JS动态修改配合CSS预处理器(less)
JS动态修改配合rem适配
(1)0.5px方案
优点:简单,不需要过多代码。
缺点:无法兼容安卓设备、 iOS 7及以下设备。
(2)伪类+transform
优点:所有场景都能满足,支持圆角(伪类和本体类都需要加border-radius)。
缺点:代码量也很大,对于已经使用伪类的元素(例如clearfix),可能需要多层嵌套。
(3)viewport + rem
优点:所有场景都能满足,一套代码,可以兼容基本所有布局。
缺点:老项目修改代价过大,只适用于新项目。
(4)border-image
优点:可以设置单条,多条边框,没有性能瓶颈的问题
缺点:修改颜色麻烦, 需要替换图片;圆角需要特殊处理,并且边缘会模糊
(5)background-image
优点:可以设置单条,多条边框,没有性能瓶颈的问题。
缺点:修改颜色麻烦, 需要替换图片;圆角需要特殊处理,并且边缘会模糊。
弹性盒中的项目设置flex-grow属性定义项目的放大比例,默认值为0,值越大,放大越厉害,且不支持负值;
而flex-shrink属性定义项目的缩小比例,默认值为1,数值越大,缩小越厉害,同样不支持负值;
flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间,浏览器根据这个属性,计算主轴是否有多余空间。他的默认值为auto,
也就是项目的本来大小。
SPA(单页应用)首屏加载速度慢怎么解决?
减小入口文件体积
静态资源本地存储
UI框架按需加载
图片资源的压缩
组件重复打包
开启Gzip压缩
使用SSR
在Vue2.0中,代码复用和抽象主要形式是组件,
然而有的情况下,仍然需要对普通DOM元素进行底层操作,
这时候就需要使用到自定义指令
应用场景:表单防止重复提交、图片懒加载、一键copy的功能
前端性能优化的手段有哪些?
加载优化(减少http请求数)、图片优化、使用CDN、开启Gzip(代码压缩)、
样式表和JS文件的优化、减少不必要的Cookie、脚本优化、前端代码结构的优化、SEO优化
栈又称堆栈,它是一种运算受限的线性表,
限定仅在表尾进行插入和删除操作的线性表,
表尾这一端被称为栈顶,相反地另一端被称为栈底,
向栈顶插入元素被称为进栈、入栈、压栈,从栈顶删除元素又称作出栈
队列:跟栈十分相似,队列是一种特殊的线性表,
特殊之处在于它只允许在表的前端(front)进行删除操作,
而在表的后端(rear)进行插入操作
进行插入操作的端称为队尾,进行删除操作的端称为队头
当队列中没有元素时,称为空队列
在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队
因为队列只允许在一端插入,在另一端删除
只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出
栈应用场景:借助栈的先进后出的特性,可以简单实现一个逆序数处的功能,
首先把所有元素依次入栈,然后把所有元素出栈并输出
队列应用场景:当需要按照一定的顺序来处理数据,而数据量在不断地变化的时候,
则需要队列来帮助解题,队列的使用广泛应用在广度优先搜索种,
例如层次遍历一个二叉树的节点值