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对象中
要防止这种问题可以使用严格模式:
“use strict”
通过使用严格模式,向JavaScript编译器暗示,你想保护自己免受这些行为的影响。当你需要时,你仍然可以使用Window。不过,你必须以明确的方式使用它。
严格模式是如何影响我们前面的例子:
-
对于 addElement 函数,当从全局作用域调用时,this 是未定义的
-
如果没有在一个变量上指定const | let | var,你会得到以下错误:
Uncaught ReferenceError: b is not defined
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
总结一下这三次面试下来我的经验是:
-
一定不要死记硬背,要理解原理,否则面试官一深入就会露馅!
-
代码能力一定要注重,尤其是很多原理性的代码(之前两次让我写过Node中间件,Promise.all,双向绑定原理,被虐的怀疑人生)!
-
尽量从面试官的问题中表现自己知识的深度与广度,让面试官发现你的闪光点!
-
多刷面经!
我把所有遇到的面试题都做了一个整理,并且阅读了很多大牛的博客之后写了解析,免费分享给大家,算是一个感恩回馈吧,有需要的朋友【点击我】免费获取。祝大家早日拿到自己心怡的工作!
篇幅有限,仅展示部分内容
我写过Node中间件,Promise.all,双向绑定原理,被虐的怀疑人生)!
-
尽量从面试官的问题中表现自己知识的深度与广度,让面试官发现你的闪光点!
-
多刷面经!
我把所有遇到的面试题都做了一个整理,并且阅读了很多大牛的博客之后写了解析,免费分享给大家,算是一个感恩回馈吧,有需要的朋友【点击我】免费获取。祝大家早日拿到自己心怡的工作!
篇幅有限,仅展示部分内容