By
被删
更新日期:
大多数情况下,前端很少遇到性能瓶颈。但如果在大型前端项目、数据量百万千万的场景下,有时候一些毫不起眼的代码习惯也可能会带来性能问题。
今天来简单介绍几种,大家在写代码的时候也可以注意。
代码细节与性能
减少函数拆解
很多时候,为了提高代码复用率以及提升代码可读性,我们习惯地将一些相同逻辑的代码进行抽离,比如下述的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
function checkTwoDimensionCross( startA: number, endA: number, startB: number, endB: number ): boolean { return !(startA > endB || endA < startB); }
function checkTwoColRangesCross( colRangeA: [number, number], colRangeB: [number, number] ): boolean { const [startColA, endColA] = colRangeA; const [startColB, endColB] = colRangeB;
return checkTwoDimensionCross(startColA, endColA, startColB, endColB); }
export function checkTwoRowRangeCross( areaA: { rowStart: number; rowEnd: number }, areaB: { rowStart: number; rowEnd: number } ): boolean { return checkTwoDimensionCross( areaA.rowStart, areaA.rowEnd, areaB.rowStart, areaB.rowEnd ); }
|
在该代码中,由于行范围和列范围的类型不一致,但为了逻辑判断一致性和方便管理,我们抽离了checkTwoDimensionCross
方法,用于判断两个一维的范围是否相交。
大多数情况下,考虑代码可读性,也比较推荐这种写法。但如果在十万百万次调用的函数方法里,多一层的函数就需要多一层调用栈的开销,其中性能的影响不可小觑。因此,我们可以将拆出去的函数合并回来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
export function checkTwoRowRangeCross( areaA: IRowRange, areaB: IRowRange ): boolean { return !(areaA.rowStart > areaB.rowEnd || areaA.rowEnd < areaB.rowStart); }
function checkTwoColRangesCross( colRangeA: IColRange, colRangeB: IColRange ): boolean { const [startColA, endColA] = colRangeA; const [startColB, endColB] = colRangeB;
return !(startColA > endColB || endColA < startColB); }
|
if else 或许性能更优
有时候我们为了偷懒,喜欢使用语法糖来缩减代码的编写,比如说判断两个字符串数组是否内容一致:
1 2 3 4 5 6 7 8 9
|
function isStringArrayTheSame( stringArrayA: string[], stringArrayB: string[] ): boolean { return stringArrayA.sort().join(",") === stringArrayB.sort().join(","); }
|
但同样的,假设这个方法被调用十万百万次,性能问题可能就会变得是否明显,不管是sort
还是数组拼接成字符串都会有一定开销。这种情况下我们可以这么写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
function isStringArrayTheSame( stringArrayA: string[], stringArrayB: string[] ): boolean { if (stringArrayA.length !== stringArrayB.length) return false;
for (const type of stringArrayA) { if (!stringArrayB.includes(type)) return false; }
return true; }
|
下面这种偷懒写法也是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function mergeStringArray( stringArrayA: string[], stringArrayB: string[] ): string[] { return Array.from(new Set(stringArrayA.concat(stringArrayB))); }
function mergeStringArray( stringArrayA: string[], stringArrayB: string[] ): string[] { const newStringArray = [].concat(stringArrayA); stringArrayB.forEach((type) => { if (!newStringArray.includes(type)) newStringArray.push(type); }); return newStringArray; }
|
低性能消耗代码判断提前
if...else
写法也有很多注意事项,最简单的莫过于尽量使执行代码提前return
。假设我们现在有这样的代码:
1 2 3 4 5 6 7
| function test(arrayA: string[], arrayB: string[]): boolean { if (costTimeFunction(arrayA, arrayB) || noCostTimeFunction(arrayA, arrayB)) { testCodeA(); } else { testCodeB(); } }
|
这样写看起来没什么问题,但假设已知costTimeFunction
函数执行会有一定的性能消耗,那么在数组长度很大、调用次数很多的情况下,我们可以将耗时较少的函数放在前面执行:
1 2 3 4 5 6 7 8
| function test(arrayA: string[], arrayB: string[]): boolean { if (noCostTimeFunction(arrayA, arrayB) || costTimeFunction(arrayA, arrayB)) { testCodeA(); return; } testCodeB(); }
|
结束语
虽然这些都是很细节的事情,有时候写代码甚至注意不到,但如果养成了思考代码性能的习惯,就可以写出更高效执行的代码。
实际上,除了简单的代码习惯以外,更多时候我们的性能问题也往往出现在不合理的代码执行流程里,这种就跟项目关系紧密,不在这里介绍啦。
查看Github有更多内容噢:https://github.com/godbasin
更欢迎来被删的前端游乐场边撸猫边学前端噢
如果你想要关注日常生活中的我,欢迎关注“牧羊的猪”公众号噢