面试题答案
一键面试对性能的影响
- 内存泄漏:如果在
componentWillUnmount
中的异步清理任务没有正确处理,当组件卸载后,这些异步任务可能仍然在执行,并且持有对组件或其内部状态的引用,导致组件及其相关资源无法被垃圾回收机制回收,从而造成内存泄漏。 - 阻塞后续操作:在频繁挂载和卸载组件的场景下,如果异步清理任务耗时较长,可能会阻塞后续组件的挂载操作,影响用户体验。
优化方法
- 使用
AbortController
(适用于支持该 API 的环境):- 可以在组件挂载时创建一个
AbortController
实例,并在异步任务中使用它。 - 在
componentWillUnmount
中调用abort
方法来取消异步任务。
import React, { Component } from'react'; class MyComponent extends Component { constructor(props) { super(props); this.abortController = new AbortController(); } componentDidMount() { const { signal } = this.abortController; // 发起异步任务 fetch('your-api-url', { signal }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => { if (error.name === 'AbortError') { // 任务被取消时的处理 console.log('任务已取消'); } else { console.error('请求错误:', error); } }); } componentWillUnmount() { this.abortController.abort(); } render() { return <div>My Component</div>; } } export default MyComponent;
- 可以在组件挂载时创建一个
- 手动管理异步任务状态:
- 定义一个标志变量来表示组件是否已经卸载。
- 在异步任务的回调中检查这个标志变量,以决定是否继续执行后续操作。
import React, { Component } from'react'; class MyComponent extends Component { constructor(props) { super(props); this.isUnmounted = false; } componentDidMount() { setTimeout(() => { if (!this.isUnmounted) { // 模拟异步操作 console.log('异步操作完成'); } }, 1000); } componentWillUnmount() { this.isUnmounted = true; } render() { return <div>My Component</div>; } } export default MyComponent;
- 使用
useEffect
的清理函数(对于函数式组件):- 在
useEffect
中返回一个清理函数,该清理函数会在组件卸载时执行。 - 如果清理函数中有异步操作,同样可以采用上述两种方式来处理异步任务。
import React, { useEffect } from'react'; const MyComponent = () => { useEffect(() => { const controller = new AbortController(); const { signal } = controller; // 发起异步任务 fetch('your-api-url', { signal }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => { if (error.name === 'AbortError') { console.log('任务已取消'); } else { console.error('请求错误:', error); } }); return () => { controller.abort(); }; }, []); return <div>My Component</div>; }; export default MyComponent;
- 在