likes
comments
collection
share

和孔乙己一起聊聊前端代码优化

作者站长头像
站长
· 阅读数 12

掌柜的让管事叫来独自落座在门口桌子边的店小二:“主顾下周要看一下进度,为嘛你这边的bug还这么多?”

店小二立马起身,一脸不屑的答道:"不是说好到月底才上线嘛,这突然袭击谁能受得了,我都连续好几天加班了;再说那个功能当时是孔乙己开发的,你要找他"; 听到孔乙己的名字,掌柜的压抑着的怒火完全从眼睛里面烧了起来,“上一个项目就是孔乙己留了很多bug,惹得大家很不爽,孔乙己何在?”

刚上完洗手间回来的孔乙己在客栈外50米远就听到了自己的名字,三步并作两步地赶了过来:“谁在背地里说我坏话,代码里面有bug是正常的,改改不就成了...”, 店小二不屑的说道:“孔乙己,来看看你写的CSS,以后主顾多了,让我如何应对的过来”;

CSS模块化

店小二打开VsCode,赫然出现孔乙己当时写的代码,一堆乱糟糟的HTML和CSS代码,一度让店小二怀疑这是新来的伙计写的;

// 下拉菜单示例
// HTML
<div class="modalSelect">
  <div class="clickText" type="button" id="modalSelect">
    下拉菜单
    <span class="jiantou"></span>
  </div>
  <div class="listdiv">
    <div><span class="text">菜单一</span></div>
    <div><span class="text">菜单二</span></div>
    <div><span class="text">菜单三</span></div>
    <div><span class="text">菜单四</span></div>
  </div>
</div>

// CSS
.modalSelect {
	display: inline-block;
}

.modalSelect .clickText {
    color: #333;
    background-color: #fff;
    border: 1px solid #ccc;
}

.modalSelect .jiantou { // ... }
.modalSelect .listdiv {}
.modalSelect .listdiv div {}
.modalSelect .listdiv div .text {}

“孔乙己,以你的技术写样式不是小意思吗? 现在less/sass那么好用,你搞起来啊”,孔乙己对着店小二呵呵笑道:“小二,你还是太年轻,前端模块化开发概念我知道啊,哎,现在做了10多年开发了,也懒得去纠结这些代码细节了”;

"你想要的效果可是这样的?"

HTML
<div class="dropdown">
  <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1">
    下拉菜单
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu">
    <li><a href="#">菜单一</a></li>
    <li><a href="#">菜单二</a></li>
    <li><a href="#">菜单三</a></li>
  </ul>
</div>

// SCSS
.dropdown {
	.dropdown-toggle {
		.caret { // ... }
	}

	.dropdown-menu {
		> li {

		}
	}
}

"对啊,就是这个效果啊,HTML和CSS也可以进行模块化开发啊;孔乙己,拜托以后用上sass可好,和大家保持一致";

孔乙己漏出邪恶的笑容,心里默默念叨着:"呵呵,小子,你还年轻,疫情之后找工作多难你是不知道啊"

jQuery依然能战

不经意间,管事发现代码里面怎么还有"$()\$.ajax()\$.extend()\$\$$,天呐,现在可是2023年啊; 掌柜的喊道:“我们的项目用的Vue还是React”, 店小二答道:“Vue 2.x”;

"那代码里面的$是怎么回事呢?"

店小二再次答道:"害,您是有所不知啊,新来的那几个伙计,刚刚从私塾毕业,也没有考个秀才,也没有打理过什么营生,听说现在私塾里面还在教jQuery啊"!

一旁的孔乙己转过身来,说道:“白猫黑猫,抓住老鼠就是好猫; 主顾只管吃蛋,不会关心是哪只鸡下的蛋,jQuery能满足需求就行”;见空气突然凝固了,孔乙己觉得有点尴尬,指着代码说道: "其实,新来的伙计这么干也没问题,只是要注意细节,注意代码优化;比如说:"

  • 提炼函数

在JavaScript开发中,我们大部分时间都在与函数打交道,所以函数有着良好的命名,函数体内逻辑要清晰明了。如果一个函数过长,不得不加上若干注释才能让函数显得易读,那这些函数就很有必要进行重构; 如果在函数中有一段代码可以被独立出来,那我们最好把这些代码放进另外一个独立的函数中。这是一种很常见的优化工作,这样做的好处主要有以下几点:

  1. 避免出现超大函数
  2. 独立出来的函数有助于代码复用
  3. 独立出来的函数更容易被覆写
  4. 独立出来的函数如果拥有一个良好的命名,它本身就起到了注释的作用
function renderList(){
	$.get('/list', function(response){
		var fragment = [];
		for(var i = 0; i < response.length; i++){
			fragment.push('<div><span>'+item.name+'</span></div>');
		}
		
		$("#wrapper").html(fragment.join(""));
	}, 'json');
}

// 进行函数分解
// 获取数据
function getListsArray(renderCallback){
	$.get('/list', function(responseArray){
    typeof renderCallback === 'function' && renderCallback(responseArray);
	}, 'json')
}

// 组装列表DOM
function getListFragment(listArray){
    var fragment = [];
		for(var i = 0; i < listArray.length; i++){
			fragment.push('<div><span>'+listArray[i].name+'</span></div>');
		}
    return fragment.join("");
}

// 替换DOM
function replaceDOM(container, element){
  $(container).html(element);
}


var getListAndRender = function(container){
  getListsArray(function(responseArray){
    replaceDOM(container, getListFragment(responseArray));
  });
}

getListAndRender("#wrapper");
  • 合并重复的条件片段

如果一个函数体内有一些条件分支语句,而这些条件分支语句内部散布了一些重复的代码,那么就有必要进行合并去重工作


var paging = function(){
  if(currentPage <= 0){
    currentPage = 0;
    jump( currentPage );
  }else if(currentPage >= totalPage){
    currentPage = totalPage;
    jump(currentPage);
  }else{
    jump(currentPage);
  }
}

// 改进
var paging = function(){
  if(currentPage <= 0){
    currentPage = 0;
  }else if(currentPage >= totalPage){
    currentPage = totalPage;
  }

  jump(currentPage);
}

  • 合理使用循环

  • 传递对象参数代替过长的参数列表

有时候一个函数有可能接收多个参数,而参数的数量越多,函数就越难理解和使用。使用该 函数的人首先得搞明白全部参数的含义,在使用的时候,还要小心翼翼,以免少传了某个参数或 者把两个参数搞反了位置。如果我们想在第 3个参数和第 4个参数之中增加一个新的参数,就会 涉及许多代码的修改

  • 尽量减少参数数量

如果调用一个函数时需要传入多个参数,那这个函数是让人望而生畏的,我们必须搞清楚这 些参数代表的含义,必须小心翼翼地把它们按照顺序传入该函数。而如果一个函数不需要传入任 何参数就可以使用,这种函数是深受人们喜爱的。在实际开发中,向函数传递参数不可避免,但 我们应该尽量减少函数接收的参数数量

  • 少用三目运算符

有一些小伙计喜欢大规模地使用三目运算符,来代替传统的 if 、 else 。理由是三目运算符性能高,代码量少。不过,这两个理由其实都很难站得住脚。即使我们假设三目运算符的效率真的比 if 、 else 高,这点差距也是完全可以忽略不计的。 在实际的开发中,即使把一段代码循环一百万次,使用三目运算符和使用 if 、 else 的时间开销处在同一个级别里。同样,相比损失的代码可读性和可维护性,三目运算符节省的代码量也可以忽略不计。让 JS文件加载更快的办法有很多种,如压缩、缓存、使用 CDN 和分域名等

// 如果条件分支逻辑简单且清晰,这无碍我们使用三目运算符:
var global = typeof window !== "undefined" ? window : this;

// 如果条件分支逻辑非常复杂,那我们最好的选择还是按部就班地编写if 、 else 。 if 、 else 语句的好处很多是:
1. 阅读相对容易
2. 修改的时候比修改三目运算符周围的代码更加方便

  • async/await解决回调问题

"哈哈, 老夫想说的是:" 写代码不能不拘小节。能写出功能健全、容易维护、易于阅读的代码非一朝一夕之功,需要大家平常就要有关注代码质量的意识,坚持代码review,互相取长补短,不积累技术债务",孔乙己有种身为师长的感觉,说出这番话让他感觉对得起自己多年撸码的身份

ES6功能增强

"孔乙己,现在大家都在用ES6了,你也给我们说道说道啊, 常用的那些方法在日常撸码中怎么用,如何优化,或者如何让效率更高",几个新来的伙计围着孔乙己七嘴八舌的说到; "好吧,跟你们说啊,ES6很好用,很多方法用起来爽得很,比如:"

数组方法: map、filer、isArray、reduce、async/await
  • map配合filter的链式调用

数组的很多方法之间是可以链式使用的,有个前提: 前面方法返回的数据依然是个数组

// 获取score >= 90 的student,并输出['name: score']格式数据
const students = [
  {name: 'James', score: 98},
  {name: 'lucy', score: 80},
  {name: 'rose', score: 90},
  {name: 'fox', score: 88}
];


let result = students.filter(student=>student.score >= 90)
                     .map(student=>`${student.name}: ${student.score}`);
  • reduce使用
// 统计所有学生的分数之和
const students = [
  {name: 'James', score: 98},
  {name: 'lucy', score: 80},
  {name: 'rose', score: 90},
  {name: 'fox', score: 88}
];

let total = students.reduce((result, student, studentIndex, array)=>{
  result += student.score;
  return result;
}, 0);
  • async/await 孔乙己指着async/await说到:"这玩意有意思啊,21世纪的技术真的让人羡慕啊,曾几何时,走出了一个藩篱,就陷入另一个 泥潭; 当年那回调地狱让劳资不堪回首,而后Promise.then又让我陷入迷茫,你们这些小伙计有福啊,能用async/await的就尽量用哦";
update = async(params)=>{
  let resultA = await this.dispatch("updateState", { params });
  let resultB = await this.dispatch("updateState", { params: resultA })
  let resultC = await this.dispatch("updateState", { params: resultB })
}

"嗯,懂了,GET到了,孔乙己真厉害!", 新来的伙计称赞到;

"好啦,好啦,我也是浅尝辄止,要不怎么连个秀才也没考中呢,你们就不要取笑我了,今天只是来个开胃菜!"

掌柜的看到孔乙己跟新来的伙计聊得很开心,嘀咕到:"老油条,搞了这么多年连个秀才都没中,也就 在新来的伙计面前嘚瑟嘚瑟";

"孔乙己,又发现你写个bug了,赶快过来看一下!"

"来喽!"

"小伙计们,散了吧,今天先跟你们聊到这里,等我bug改完再给你们念叨念叨; 要知后事如何,请听下回分解";

结语

本故事纯属虚构,如有类同,实属巧合;

  • 年少嘲笑"孔乙己",如今已经活成了"孔乙己"
  • 有空请关注孔乙己完善代码示例
  • 后记敬请期待