import styles from ‘…/styles/Home.module.css’
import Timer from ‘…/components/Timer’;
export default function Home() {
const [showTimer, setShowTimer] = useState();
const onFinish = () => setShowTimer(false);
return (
{showTimer ? (
): (
<button onClick={() => setShowTimer(true)}>
Retry
)}
)
}
在 Retry
按钮上单击几次后,这是使用Chrome Dev Tools获取内存使用的结果:
当我们点击重试按钮时,可以看到分配的内存越来越多。这说明之前分配的内存没有被释放。计时器仍然在运行而不是被替换。
怎么解决这个问题?setInterval
的返回值是一个间隔 ID,我们可以用它来取消这个间隔。在这种特殊情况下,我们可以在组件卸载后调用 clearInterval
。
useEffect(() => {
const intervalId = setInterval(() => {
if (currentCicles.current >= cicles) {
onFinish();
return;
}
currentCicles.current++;
}, 500);
return () => clearInterval(intervalId);
}, [])
有时,在编写代码时,很难发现这个问题,最好的方式,还是要把组件抽象化。
这里使用的是React,我们可以把所有这些逻辑都包装在一个自定义的 Hook 中。
import { useEffect } from ‘react’;
export const useTimeout = (refreshCycle = 100, callback) => {
useEffect(() => {
if (refreshCycle <= 0) {
setTimeout(callback, 0);
return;
}
const intervalId = setInterval(() => {
callback();
}, refreshCycle);
return () => clearInterval(intervalId);
}, [refreshCycle, setInterval, clearInterval]);
};
export default useTimeout;
现在需要使用setInterval
时,都可以这样做:
const handleTimeout = () => …;
useTimeout(100, handleTimeout);
现在你可以使用这个useTimeout Hook
,而不必担心内存被泄露,这也是抽象化的好处。
2.事件监听
Web API提供了大量的事件监听器。在前面,我们讨论了setTimeout
。现在来看看 addEventListener
。
在这个事例中,我们创建一个键盘快捷键功能。由于我们在不同的页面上有不同的功能,所以将创建不同的快捷键功能
function homeShortcuts({ key}) {
if (key === ‘E’) {
console.log(‘edit widget’)
}
}
// 用户在主页上登陆,我们执行
document.addEventListener(‘keyup’, homeShortcuts);
// 用户做一些事情,然后导航到设置
function settingsShortcuts({ key}) {
if (key === ‘E’) {
console.log(‘edit setting’)
}
}
// 用户在主页上登陆,我们执行
document.addEventListener(‘keyup’, settingsShortcuts);
看起来还是很好,除了在执行第二个 addEventListener
时没有清理之前的 keyup
。这段代码不是替换我们的 keyup
监听器,而是将添加另一个 callback
。这意味着,当一个键被按下时,它将触发两个函数。
要清除之前的回调,我们需要使用 removeEventListener
:
document.removeEventListener(‘keyup’, homeShortcuts);
重构一下上面的代码:
function homeShortcuts({ key}) {
if (key === ‘E’) {
console.log(‘edit widget’)
}
}
// user lands on home and we execute
document.addEventListener(‘keyup’, homeShortcuts);
// user does some stuff and navigates to settings
function settingsShortcuts({ key}) {
if (key === ‘E’) {
console.log(‘edit setting’)
}
}
// user lands on home and we execute
document.removeEventListener(‘keyup’, homeShortcuts);
document.addEventListener(‘keyup’, settingsShortcuts);
根据经验,当使用来自全局对象的工具时,需要灰常小心。
3.Observers
Observers 是一个浏览器的 Web API功能,很多开发者都不知道。如果你想检查HTML元素的可见性或大小的变化,这个就很强大了。
IntersectionObserver
接口 (从属于Intersection Observer API) 提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport
)交叉状态的方法。祖先元素与视窗(viewport
)被称为根(root
)。
尽管它很强大,但我们也要谨慎的使用它。一旦完成了对对象的观察,就要记得在不用的时候取消它。
看看代码:
const ref = …
const visible = (visible) => {
console.log(It is ${visible}
);
}
useEffect(() => {
if (!ref) {
return;
}
observer.current = new IntersectionObserver(
(entries) => {
if (!entries[0].isIntersecting) {
visible(true);
} else {
visbile(false);
}
},
{ rootMargin: -${header.height}px
},
);
observer.current.observe(ref);
}, [ref]);
上面的代码看起来不错。然而,一旦组件被卸载,观察者会发生什么?它不会被清除,那内存可就泄漏了。我们怎么解决这个问题呢?只需要使用 disconnect
方法:
const ref = …
const visible = (visible) => {
console.log(It is ${visible}
);
}
useEffect(() => {
if (!ref) {
return;
}
observer.current = new IntersectionObserver(
(entries) => {
if (!entries[0].isIntersecting) {
visible(true);
} else {
visbile(false);
}
},
{ rootMargin: -${header.height}px
},
);
observer.current.observe(ref);
return () => observer.current?.disconnect();
}, [ref]);
4. Window Object
向 Window 添加对象是一个常见的错误。在某些场景中,可能很难找到它,特别是在使用 Window Execution上下文中的this
关键字。看看下面的例子:
function addElement(element) {
if (!this.stack) {
this.stack = {
elements: []
}
}
this.stack.elements.push(element);
}
它看起来无害,但这取决于你从哪个上下文调用addElement
。如果你从Window Context调用addElement,那就会越堆越多。
另一个问题可能是错误地定义了一个全局变量:
var a = ‘example 1’; // 作用域限定在创建var的地方
b = ‘example 2’; // 添加到Window对象中
要防止这种问题可以使用严格模式:
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
系的自学效果低效漫长且无助。**
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-AfTvHaol-1715289187604)]
[外链图片转存中…(img-CXk6KqlL-1715289187605)]
[外链图片转存中…(img-Op2163FA-1715289187605)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!