前端面试题——React篇


前言

准备了一些高频面试题,有需要的小伙伴可以收藏,需要的时候看看,也会持续更新。


1.useEffect是异步还是同步

useEffect的执行是异步的,这主要是为了确保它不会阻塞浏览器的绘制过程,从而保持用户界面的响应性。

为何是异步

1、避免阻塞浏览器绘制:
如果 useEffect 同步执行,那么在组件渲染过程中,所有的副作用逻辑(比如数据获取、DOM 操作、订阅等)都必须执行完毕,浏览器才能继续绘制。这会导致用户界面在副作用执行期间停顿,影响用户体验。

2、保持数据一致性:
React 的渲染过程是异步和批处理的。在渲染过程中,多个状态更新可能被批处理。如果 useEffect 是同步执行的,可能会导致在渲染过程中状态的不一致,因为副作用可能依赖于最新的渲染结果。异步执行 useEffect 确保了在所有 DOM 更新完成后再运行副作用逻辑,从而保证数据的一致性。

3、类比于生命周期:
在类组件中,副作用通常在 componentDidMountcomponentDidUpdate 生命周期方法中执行。React 将这些方法的执行也设计为异步,以便优化性能和用户体验。useEffect 是函数组件中的等价 Hook,因此也遵循相同的异步设计原则。

4、更好的性能优化:
React 可以通过异步执行副作用来更好地管理性能。比如,React 可以在必要时跳过不需要的副作用,或在空闲时间(通过 requestIdleCallback)执行一些较低优先级的副作用,从而提高应用的整体性能。

如何拿到最新的数据

1、使用useEffect依赖项:
useEffect 的第二个参数是一个数组,包含所有影响副作用执行的状态或变量。当这些依赖项发生变化时,useEffect 会重新执行。确保将数据作为依赖项传递给 useEffect,这样可以保证在数据更新后,副作用会重新执行,从而拿到最新的数据。

2、使用 async/await:
如果你在 useEffect 中使用了异步函数(比如 fetch),你可以使用 async/await 来确保在数据完全获取后再更新状态。

3、使用setTimeout:使用setTimeout时,将延迟时间设置为0或者省略,可拿到需要的最新数据。

  • 执行机制setTimeoutuseEffect在一起有多余的感觉,因为useEffect本身就是异步,而setTimeout也是异步的。即使没有 setTimeout,React 也会在组件渲染完成后立即执行,所以,setTimeout并不会改变其执行时机。
  • 性能考虑:虽然将时间设置为 0 的 setTimeout 通常被用来将代码推迟到下一个事件循环中执行,但在这里,它只是增加了额外的无谓开销,没有提供任何实际的优势。这可能会对性能产生微小的负面影响。

2.微任务和宏任务

概念

1、微任务(microtask):
微任务是指在当前任务执行完毕后立即执行的任务。Promise回调函数、async/await(返回的也是一个promise)、process.nextTick、等都是微任务的例子。在React中,更新状态和执行副作用(如生命周期方法、钩子函数、effect hook等)通常被视为微任务。这意味着,当React组件的状态更新时,React会将相应的更新计划为微任务,以确保它们在当前任务执行结束后立即执行。

2、宏任务(macrotask):
宏任务是指需要在事件循环的下一个迭代中执行的任务。定时器(setTimeout、setInterval)、I/O 操作、UI 渲染等通常被视为宏任务。在React中,调度新的组件渲染、处理用户输入等也被认为是宏任务。

优点

在React中,通过将任务分解为微任务和宏任务,可以实现异步更新优化性能。例如,React可以利用微任务将多个状态更新合并成一个,从而减少渲染次数,提高性能。同时,宏任务的使用也确保了React能够在用户交互等事件之后及时更新UI,提供良好的用户体验。

3.事件循环(Event Loop)

概念

事件循环(Event Loop)是Javascript运行时环境的一部分,它负责管理代码的执行顺序,简单来说就是Javascript的一种运行机制,解决浏览器的单线程问题。
Javascript单线程任务从时间上分为同步任务和异步任务,而异步任务又分为宏任务(macrotask)和微任务(microtask)。

执行机制

  1. 执行全局同步代码,将其中的函数调用推入调用栈中。
  2. 当调用栈为空时,事件循环开始执行微任务队列中的任务,直到微任务队列为空。
  3. 从任务队列中取出一个任务,并将其推入调用栈中执行。
  4. 重复上述步骤,直到任务队列和微任务队列都为空。

4.React性能优化手段

  1. 避免不必要的渲染合理使用shouldComponentUpdateReact.PureComponent,使用 shouldComponentUpdate 来控制组件是否需要重新渲染。React.PureComponent 自动实现了 shouldComponentUpdate,浅比较 props 和 state,函数组件可使用React.memo
  2. 使用合适的数据结构和状态管理:使用不可变数据结构(如 Immutable.js)有助于高效地进行数据比较和变更检测;适当地提升状态,避免在层级过深的组件树中传递大量数据。使用 React.Context 来避免深层级的 props 传递。
  3. 避免匿名函数和对象:在渲染方法中避免定义匿名函数和对象,因为每次渲染都会生成新的引用,导致子组件的重新渲染。
  4. 代码分割和懒加载:使用 React.lazyReact.Suspense 进行代码分割和组件懒加载,减少初始加载时间。
  5. 使用虚拟化列表:对于长列表,使用虚拟化技术(如 react-windowreact-virtualized)来只渲染视口中的项目,避免渲染大量的 DOM 节点。
  6. 合理使用 useCallbackuseMemo:对于函数和复杂计算结果,使用 useCallbackuseMemo 来避免不必要的重新创建。
  7. 列表项使用 key 属性key 属性帮助 React 高效地进行 DOM diff 算法,从而减少不必要的 DOM 操作,当列表发生变化时,React 可以使用 key 来确定哪些元素需要更新、插入或删除。
  8. 使用生产模式:确保在生产环境中使用 React 的生产版本。开发版本包含额外的警告和检查,性能较低,生产版本会进行代码压缩和性能优化。
  • 12
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小童不学前端

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值