📒 TS 类型系统实现大数相加
一位数相加,总共只有 100 种情况,为了提高性能,可以选择 打表 。
📒 浏览器渲染中的合成层与 will-change
合成就是将页面的各个部分分成多个层、单独 光栅化
(浏览器根据文档的结构、每个元素的样式、页面的几何形状和绘制顺序转换为屏幕上的像素的过程)它们并在合成器线程中合成为一个页面的技术。
一般来说,拥有一些特定属性的渲染层,会被浏览器自动提升为合成层。合成层拥有单独的图层(GraphicsLayer),和其他图层之间无不影响。而其它不是合成层的渲染层,则和第一个拥有图层的父层共用一个,也就是普通文档流中的内容,我们看一些常见的提升为合成层的属性。
- 设置
transform: translateZ(0)
backface-visibility: hidden
指定当元素背面朝向观察者时是否可见will-change
该属性告诉浏览器该元素会有哪些变化,这样浏览器可以提前做好对应的优化准备工作video
、canvas
、iframe
等元素
使用 transform 和 opacity 来实现动画
在开发中经常会实现一些动画,有时候我们可能会选择改变 top/left 去实现,那么这个节点的渲染会发生在普通文档流中。而使用 transform
和 opacity
实现动画能够让节点被放置到一个独立合成层中进行渲染绘制,动画不会影响其他图层,并且 GPU 渲染相比 CPU 能够更快,这会让你的动画变的更加流畅。
按照下面的操作打开查看帧率的界面:
通过 transform
来实现动画,页面的 fps
能够稳定在 60 左右,而通过 left
来实现存在波动,fps
大概稳定在 30 左右,这会影响你的用户体验指标。
⭐️ 前端 Code Review 不完全指北(万字长文,50+case)
📒 Node.js 相关
Node.js 适合 IO 密集型任务,例如处理网络请求、文件 IO 等等;
Node.js 不适合 CPU 密集型任务,例如 MD5、SHA 加密算法等;
📒 什么是 inode
inode
(index nodes) 是操作系统中重要的概念,是一种文件数据结构,用于存储有关除名称和数据之外的任何 Linux 文件的信息。
📒 gitlab上代码回滚把自己坑了后, 陷入思考🤔"bug是谁"?
⭐️ 提交代码的时候使用 rebase
一般提交代码都是先本地 commit
,然后执行 git pull
将仓库的代码拉取到本地 merge,然后再 push
到仓库。这样会导致时间线很不干净,提交记录中混杂很多 merge 分支的无用记录。
在拉取仓库代码的时候,我们可以不进行合并,而是使用 rebase(变基),直接把我们原先的基础变掉,变成以别人修改过后的新代码为基础,把我们的修改在这个新的基础之上重新进行。使用变基之后,就可以使我们的时间线变得非常干净。
📒 如何使用 VS Code 任务
开发经典模式:从主仓库 fork => 从个人仓库提 Merge Request
【手把手】学会VS Code"任务"神技,成为项目组最靓的崽!
📒 如何分析每行代码的执行耗时
首先使用 Performance 工具分析页面性能。
在分析性能的时候,为排除插件的影响,需要启用无痕模式
在火焰图中找到长任务,点击顶部 Task,点击 Button-Up,这时候可以看到根据耗时列出的调用栈:
找到那个执行耗时最长的,然后点击右侧源码地址,可以跳到 source 对应的源码:
📒 关于数组遍历方法的比较
- 相比
forEach
,map
性能略差一些,因为需要创建新数组 - 数据量大的时候,手写
for
循环性能明显优于forEach
和map
- 倒序
for
循环性能最好,因为只访问了一次array.length
// 正序
for (let i=0; i<arr.length; i++)
// 倒序
for (let i=arr.length-1; i>=0; i--) - 如果想提升正序遍历性能,可以这样写
for (let i=0, len=arr.length-1; i<len; i++)
- 无论遍历数组还是对象,都尽量少用
for...in
循环,性能比较烂
- 倒序
- 无论
new Array()
还是Array.from()
性能都不如写一个for
循环往空数组里面push
- 另外不推荐使用
[].fill()
方法,TS 无法推导类型,建议使用Array.from({length: 10}, () => 1)
的方式
📒 如何指定一个项目所需的 node 最小版本
指定一个项目所需的 node 最小版本,这属于一个项目的质量工程。我们可以在 package.json
中的 engines
字段中指定 Node 版本号:
{
"engines": {
"node": ">=14.0.0"
}
}
如果本地运行的 Node 版本不匹配,yarn 将会报错,npm 则会打印警告信息。engines
字段不仅可以用于前端项目,也可用于第三方库。
如果项目的 package.json
中没用 engines
字段,可查看 Dockerfile 中 node 镜像确定项目所需的 node 版本号。
📒 Vue SFC playground
研究下插槽的实现
📒 写一个 Vue3 自定义指令
Vue 自定义指令的范式:
const lazyPlugin = {
install (app, options) {
app.directive('lazy', {
// install 方法的第一个参数可以拿到 Vue 构造器
// 这块可以参考 Vue.use 源码
})
}
}
export default lazyPlugin
在项目中使用如下:
import { createApp } from 'vue'
import App from './App.vue'
import lazyPlugin from 'vue3-lazy'
createApp(App).use(lazyPlugin, {
// 添加一些配置参数
})
📒 useCallback
使用场景
在 React 中经常需要将父组件定义的方法传入子组件(即事件钩子,也可以看作子组件状态提升到父组件),例如:
const Parent = () => {
const handleSearch = (val) => {
console.log("搜索结果:", val);
}
return <Input onSearch={handleSearch} />
}
const Input = React.memo(({ onSearch }) => {
return (
<form onSubmit={(e) => {
const submitData = Array.from(
e.target.childNodes,
item => ({ name: item.name, value: item.value })
);
onSearch(submitData);
}}>
<input type="text" name="search" />
</form>
)
})
在上面的代码中,如果父组件重新渲染,则会导致 handleSearch
方法重新生成,进而导致 onSearch
prop 改变,即使子组件用了 React.memo
,子组件还是会重新渲染。在这种情况下,就可以使用 useCallback
缓存函数,避免函数重复生成,进而避免子组件重复渲染,提高性能:
const Parent = () => {
const handleSearch = React.useCallback((val) => {
console.log("搜索结果:", val);
}, []);
return <Input onSearch={handleSearch} />
}
注意 useCallback
需要和 React.memo
一起使用。如果不用 React.memo
,只要父组件重新渲染,即使 prop 没有改变,子组件还是会重新渲染
📒 前端工程化系列文章
📒 ES 新语法 Array.prototype.groupBy
一个专门用来做数据分组的提案 Array.prototype.groupBy
已经到达 Stage 3
:
const array = [1, 2, 3, 4, 5];
// groupBy groups items by arbitrary key.
// In this case, we're grouping by even/odd keys
array.groupBy((num, index, array) => {
return num % 2 === 0 ? 'even': 'odd';
});
// => { odd: [1, 3, 5], even: [2, 4] }