1. 说一下你理解的闭包,以及使用场景
闭包是指有权访问另一个函数作用域中变量的函数。
形成闭包的原因是因为函数对外部作用域存在引用,导致成闭包。
闭包的作用
- 保存函数内的一些值,形成内部属性和方法私有化
- 延长变量的生命周期
闭包使用场景
- 使用闭包模拟私有方法(模块化方案)
- 柯里化函数
- 计数器(),延迟调用(节流防抖),回调等
2. html中defer和async
script标签的defer和async只对外部脚本有效,defer和async都会让脚本异步加载,但是defer加载完脚本并不立即执行,而是等待后续文档渲染加载完毕后执行。async则是加载脚本立刻执行,在执行js脚本时会阻塞dom的渲染。
defer是指脚本可以延迟到文档完全解析和显示时再执行async是指脚本立即下载,不妨碍页面中的其他操作,比如下载其他资源或等待加载其他脚本。
3. react中setState是异步还是同步
react在v18之前setState是异步的,但这仅限于react事件和生命周期中。设计为异步,是为了提升性能,并且保持state和props是最新的值。(如果同步更新了state,但是还没有执行render函数,那么state和props不能保持同步;)在setTimeout和原生的Dom事件里面setState是同步的。
4. 事件循环
事件循环是js的执行机制。在 js 中,任务分为宏任务(macrotask)和微任务(microtask),这两个任务分别维护一个队列,均采用先进先出的策略进行执行。同步执行的任务都在宏任务上执行。
具体步骤
- 代码执行,先按顺序取出一个宏任务;
- 宏任务中碰到微微任务把它放入微任务队列;
- 等待当前宏任务执行完毕,则从微任务中执行,如果有任务采用先进先出的顺序执行微任务,直到执行完所有微任务;
- GUI 渲染;
- 回到步骤 1,直到宏任务执行完毕,进行下一个宏任务;
宏任务主要有:script(整体代码)、setTimeout、setInterval、I/O、UI 交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)。
微任务主要有:Promise.then、 MutationObserver、 process.nextTick(Node.js 环境)。
5. 说一下防抖,节流实现
防抖是指将多次执行变为最后一次执行。
function debounce(fn, delay) {
let timer = null;
return () => {
if (timer) clearTimeout(timer);
timer = setTimeout(fn, delay)
}
}
节流是指将多次执行变成每隔一段时间执行
function throttle(fn, delay) {
let flag = true;
if (!flag) return;
return () => {
setTimeout(() => {
fn();
flag = false;
}, delay);
}
}
6. 如何实现图片懒加载,除了监听滚动条事件,还有什么api可以实现。
-
通过 onscroll 事件与
getBoundingClientRectAPI 实现图片的懒加载方案 -
通过 Intersection Observer(交叉观察器)实现比监听 onscroll 性能更佳的图片懒加载方案
-
通过
content-visibility: auto实现图片资源的延迟渲染,视觉延迟 -
通过
loading=lazyHTML 属性实现图片懒加载 -
通过
decoding=asyncHTML 属性实现图片的异步解码
7. 重排和重绘,怎么避免重排问题
重排是指页面的几何属性发生变化,需要重新计算,比如width、height改变。重绘事指外观属性发生变化,需要重新绘制,比如background发生改变,需要重新绘制的过程。重排一定会发生重绘,重绘不一定会发生重排。
8. 如何避免重排
- 减少Dom操作,需要创建多个DOM节点时,使用DocumentFragment一次性创建;
- 元素上下移动,使用translate代替top
- 复杂的动画使用定位,absolute/fiexd
- 使用className批量修改样式
9. 说说项目中遇到的难点
10. 缓存
11. 性能优化
12. hook、类组件与普通函数的区别
-
函数式组件是一个纯函数,它是需要接受props参数并且返回一个React元素就可以了。class组件是需要继承React.Component的,而且class组件需要创建render并且返回React元素,语法上来讲更复杂。
-
函数式组件可以直接调用,返回一个新的React元素;类组件在调用时是需要创建一个实例的,然后通过调用实例里的render方法来返回一个React元素。
-
函数式组件没有状态管理,类组件有状态管理(生命周期和内部状态)。
-
类组件没有具体的要求。函数式组件一般是用在大型项目中来分割大组件(函数式组件不用创建实例,所以更高效),一般情况下能用函数式组件就不用类组件,提升效率。
-
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。也就是说在React 16.8之后函数组件就可以使用state以及其他的react特性。有了hook之后函数组件式编程使react项目性能更优,代码更加简洁。
用法区别
- 在普通函数内部你不可以使用hook,自定义hook内部可以用其他的hook
- 自定义hook名字必须是 useXxx,而普通函数是 xxx , 函数组件是 Xxx;
- 在这里,我们可以观察到,函数组件 和 useXxx都是可以在里面使用hook的。
- 那么,函数组件 和 自定义hook 不同点: return 的东西不同 ,一个是 return(),一个是 return { state,setStet,xxx,yyy }。或 [ state , setState ]
- 自定义Hook 不是非用不可,没有也不影响业务。 使用自定义hook是为了让整体代码更简洁,更好复用。
13. Fiber
Fiber(一种核心算法)其实就是在react版本v16之后的虚拟dom。因为在v16之前采用深度优先遍历去遍历节点,这样会导致树庞大和中断了就不能恢复的问题。