# 写让别人能读懂的代码+网页性能管理详解

“复杂的代码往往都是新手所写，只有经验老道的高手才能写出简单，富有表现力的代码”

1. 让别人能读懂的代码
2. 可扩展的代码
3. 可测试的代码(代码应该具备可测试性，对没有可测试性的代码写测试，是浪费生命的表现)

• 代码越少，Bug也越少
• 没有重复逻辑的代码更易于维护，当你修复了一个bug，如果相同的逻辑还出现在另外一个地方，而你没意识到，你有没有觉得自己很冤？

• 简洁(Terse)
• 具有表达力(Expressive)
• 只做一件事(Do one thing)

1.拒绝注释，用代码来阐述注释

```/// <summary>
/// !@#\$%^&^&*((!@#\$%^&^&*((!@#\$%^&^&*((!@#\$%^&^&*((
/// </summary>
/// <returns></returns>
public decimal GetCash()
{
//!@#\$%^&^&*((!@#\$%^&^&*((
var a = new List<decimal>() { 2m, 3m, 10m };
var b = 2;
var c = 0m;
//!@#\$%^&^&*((!@#\$%^&^&*((!@#\$%^&^&*((
foreach (var p in a)
{
c += p*b;
}
return c;
}```

```public decimal CalculateTotalCash()
{
var prices=new List<decimal>(){2m,3m,10m};
var itemCount = 2;
return prices.Sum(p => p*itemCount);
}```

2. 为布尔变量赋值

```public bool IsAdult(int age)
{
if (age > 18)
{
}
else
{
}
}```

```public bool IsAdult(int age)
{
var isAdult = age > 18;
}```

3.双重否定的条件判断

```if (!isNotRemeberMe)
{

}```

```if (isRemeberMe)
{

}```

4.拒绝HardCode,拒绝挖坑

```if (carName == "Nissan")
{

}```

```if (car == Car.Nissan)
{

}```

5.拒绝魔数，拒绝挖坑

```if (age > 18)
{

}```

```const int adultAge = 18;
{

}```

6.复杂的条件判断

```if (job.JobState == JobState.New
|| job.JobState == JobState.Submitted
|| job.JobState == JobState.Expired
|| job.JobTitle.IsNullOrWhiteSpace())
{
//....
}```

```if (CanBeDeleted(job))
{
//
}

private bool CanBeDeleted(Job job)
{
var invalidJobState = job.JobState == JobState.New
|| job.JobState == JobState.Submitted
|| job.JobState == JobState.Expired;
var invalidJob = string.IsNullOrEmpty(job.JobTitle);

return invalidJobState || invalidJob;
}```

7.嵌套判断

```var isValid = false;
{
{
if (!string.IsNullOrEmpty(user.Email))
{
isValid = true;
}
}
}
return isValid;```

```if (string.IsNullOrEmpty(user.UserName)) return false;
if (string.IsNullOrEmpty(user.Email)) return false;
return true;```

8.使用前置条件

```if (!string.IsNullOrEmpty(userName))
{
{
//register
}
else
{
throw new ArgumentException("user password can not be empty");
}
}
else
{
throw new ArgumentException("user name can not be empty");
}```

```if (string.IsNullOrEmpty(userName)) throw new ArgumentException("user name can not be empty");
//register```

9.参数过多，超过3个

```public void RegisterUser(string userName, string password, string email, string phone)
{

}```

```public void RegisterUser(User user)
{

}```

10.方法签名中含有布尔参数

```public void RegisterUser(User user, bool sendEmail)
{

}```

```public void RegisterUser(User user)
{

}

public void SendEmail(User user)
{

}```

10.写具有表达力的代码

```private string CombineTechnicalBookNameOfAuthor(List<Book> books, string author)
{
var filterBooks = new List<Book>();

foreach (var book in books)
{
if (book.Category == BookCategory.Technical && book.Author == author)
{
}
}
var name = "";
foreach (var book in filterBooks)
{
name += book.Name + "|";
}
return name;
}```

```private string CombineTechnicalBookNameOfAuthor(List<Book> books, string author)
{
var combinedName = books.Where(b => b.Category == BookCategory.Technical)
.Where(b => b.Author == author)
.Select(b => b.Name)
.Aggregate((a, b) => a + "|" + b);

return combinedName;
}```

# 网页性能管理详解

## 一、网页生成的过程

1. HTML代码转化成DOM
2. CSS代码转化成CSSOM（CSS Object Model）
3. 结合DOM和CSSOM，生成一棵渲染树（包含每个节点的视觉信息）
4. 生成布局（layout），即将所有渲染树的所有节点进行平面合成
5. 将布局绘制（paint）在屏幕上

"生成布局"（flow）和"绘制"（paint）这两步，合称为"渲染"（render）。

## 二、重排和重绘

• 修改DOM
• 修改样式表
• 用户事件（比如鼠标悬停、页面滚动、输入框键入文字、改变窗口大小等等）

## 三、对于性能的影响

`div.style.color = 'blue';div.style.marginTop = '30px';`

`div.style.color = 'blue';var margin = parseInt(div.style.marginTop);div.style.marginTop = (margin + 10) + 'px';`

• offsetTop/offsetLeft/offsetWidth/offsetHeight
• scrollTop/scrollLeft/scrollWidth/scrollHeight
• clientTop/clientLeft/clientWidth/clientHeight
• getComputedStyle()

`// baddiv.style.left = div.offsetLeft + 10 + "px";div.style.top = div.offsetTop + 10 + "px";// goodvar left = div.offsetLeft;var top  = div.offsetTop;div.style.left = left + 10 + "px";div.style.top = top + 10 + "px";`

• 样式表越简单，重排和重绘就越快。
• 重排和重绘的DOM元素层级越高，成本就越高。
• table元素的重排和重绘成本，要高于div元素

## 四、提高性能的九个技巧

```// badvar left = 10;var top = 10;el.style.left = left + "px";el.style.top  = top  + "px";// good
el.className += " theclassname";// goodel.style.cssText += "; left: " + left + "px; top: " + top + "px;";```

## 六、开发者工具的Timeline面板

Chrome浏览器开发者工具的Timeline面板，是查看"刷新率"的最佳工具。这一节介绍如何使用这个工具。

Timeline面板提供两种查看方式：横条的是"事件模式"（Event Mode），显示重新渲染的各种事件所耗费的时间；竖条的是"帧模式"（Frame Mode），显示每一帧的时间耗费在哪里。

• 蓝色：网络通信和HTML解析
• 黄色：JavaScript执行
• 紫色：样式计算和布局，即重排
• 绿色：重绘

## 七、window.requestAnimationFrame()

```function doubleHeight(element) {
var currentHeight = element.clientHeight;
element.style.height = (currentHeight * 2) + 'px';}elements.forEach(doubleHeight);```

```function doubleHeight(element) {
var currentHeight = element.clientHeight;
window.requestAnimationFrame(function () {
element.style.height = (currentHeight * 2) + 'px';
});}elements.forEach(doubleHeight);```

```\$(window).on('scroll', function() {
window.requestAnimationFrame(scrollHandler);});```

```var rAF = window.requestAnimationFrame;var degrees = 0;function update() {
div.style.transform = "rotate(" + degrees + "deg)";
console.log('updated to degrees ' + degrees);
degrees = degrees + 1;
rAF(update);}rAF(update);```

## 八、window.requestIdleCallback()

`requestIdleCallback(fn);`

`requestIdleCallback(fn, 5000);`

```requestIdleCallback(function someHeavyComputation(deadline) {
doWorkIfNeeded();
}

if(thereIsMoreWorkToDo) {
requestIdleCallback(someHeavyComputation);
}});```

（1）timeRemaining() 方法

timeRemaining() 方法返回当前帧还剩余的毫秒。这个方法只能读，不能写，而且会动态更新。因此可以不断检查这个属性，如果还有剩余时间的话，就不断执行某些任务。一旦这个属性等于0，就把任务分配到下一轮`requestIdleCallback`

（2）didTimeout属性

deadline对象的 `didTimeout` 属性会返回一个布尔值，表示指定的时间是否过期。这意味着，如果回调函数由于指定时间过期而触发，那么你会得到两个结果。

• timeRemaining方法返回0
• didTimeout 属性等于 true

```function myNonEssentialWork (deadline) {
doWorkIfNeeded();

requestIdleCallback(myNonEssentialWork);}requestIdleCallback(myNonEssentialWork, 5000);```

requestIdleCallback 是一个很新的函数，刚刚引入标准，目前只有Chrome支持。

## 九、参考链接

• Domenico De Felice, How browsers work
• Stoyan Stefanov, Rendering: repaint, reflow/relayout, restyle
• Addy Osmani, Improving Web App Performance With the Chrome DevTools Timeline and Profiles
• Tom Wiltzius, Jank Busting for Better Rendering Performance
• Paul Lewis, Using requestIdleCallback

（完）

0 条评论

• ### 几个比较有意思的JS脚本

1.获取内网和公网真实IP地址（引用地址） 代码太长，见原文链接 2.获得flash版本（在线地址） ? <!DOCTYPE html> <html> <hea...

• ### .Net中的AOP读书笔记系列之AOP介绍

AOP是什么？ Hello，World！ 小结 本系列的源码本人已托管于Coding上：点击查看，想要注册Coding的可以点击该连接注册。 本系列的实验环境：...

• ### 跨站请求伪造（CSRF/XSRF）

简介 　　CSRF（Cross-site request forgery跨站请求伪造，也被称为“One Click Attack”或者Session Ridin...

• ### 史上最烂的项目：苦撑 12 年，600 多万行代码

你见过最烂的项目，撑了多长时间才完蛋？六个月？一年？今天介绍的这个奇葩项目，不但一开始就烂得透透的，还硬撑了12年多，直到项目负责人被逮起来丢进监狱才完事。

• ### 我的天！史上最烂的项目：苦撑 12 年，600 多万行代码...

今天介绍的这个奇葩项目，不但一开始就烂得透透的，还硬撑了 12 年多，直到项目负责人被逮起来丢进监狱才完事。

• ### 史上最烂的项目：苦撑 12 年，600 多万行代码

你见过最烂的项目，撑了多长时间才完蛋？六个月？一年？今天介绍的这个奇葩项目，不但一开始就烂得透透的，还硬撑了12年多，直到项目负责人被逮起来丢进监狱才完事。

• ### 史上最烂的项目：苦撑 12 年，600 多万行代码!

你见过最烂的项目，撑了多长时间才完蛋？六个月？一年？今天介绍的这个奇葩项目，不但一开始就烂得透透的，还硬撑了12年多，直到项目负责人被逮起来丢进监狱才完事。

• ### 谈拾取摄像机拍摄景物的颜色转化为指定颜色Demo心得

版权声明：本文为博主原创文章，遵循 CC 4.0 BY-SA 版权协议，转载请附上原文出处链接和本声明...

• ### 业务复杂=if else？刚来的大神竟然用策略+工厂彻底干掉了他们！

首先可读性，不言而喻，过多的if-else代码和嵌套，会使阅读代码的人很难理解到底是什么意思。尤其是那些没有注释的代码。

• ### 使用策略+工厂模式彻底干掉代码中的if else！

对于业务开发来说，业务逻辑的复杂是必然的，随着业务发展，需求只会越来越复杂，为了考虑到各种各样的情况，代码中不可避免的会出现很多if-else。