maintainable javascript

70
Maintainable Javascript 写高效可维护JS@HectorGuo

Upload: haixu-hector-guo

Post on 08-Feb-2017

62 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Maintainable Javascript

Maintainable Javascript编写高效可维护的JS代码

@HectorGuo

Page 2: Maintainable Javascript

可维护性

Page 3: Maintainable Javascript

Programs are meant to be read by humans and only incidentally for computers to execute

程序主要是给人读的,其次才是让计算机拿来

运行的

- H. Abelson and G. Sussman,

The Structure and Interpretation of Computer Programs

Page 4: Maintainable Javascript

代码规范的作用

帮助团队相互间更好地通过代码来交流

Page 5: Maintainable Javascript
Page 6: Maintainable Javascript
Page 7: Maintainable Javascript
Page 8: Maintainable Javascript

4空格缩进

Tab缩进

Page 9: Maintainable Javascript

if (JSV.typeOf(items) === "array") {

for (x = 0, xl = properties.length; x < xl; ++x) {

itemSchema = items[x] || additionalProperties;

if (itemSchema !== false) {

itemSchema.validate(properties[x], report, instance, schema, x);

} else {

report.addError(instance, schema, "additionalProperties",

"Additional items are not allowed", itemSchema);

}

}

}

Page 10: Maintainable Javascript

if (JSV.typeOf(items) === "array") {

for (x = 0, xl = properties.length; x < xl; ++x) {

itemSchema = items[x] || additionalProperties;

if (itemSchema !== false) {

itemSchema.validate(properties[x], report, instance, schema,

x);

} else {

report.addError(instance, schema, "additionalProperties",

"Additional items are not allowed", itemSchema);

}

}

}

https://github.com/jdc0589/JsFormat

Page 11: Maintainable Javascript

/**

* A low-level selection function that works with Sizzle's compiled

* selector functions

* @param {String|Function} selector A selector or a pre-compiled

* selector function built with Sizzle.compile

* @param {Element} context

* @param {Array} [results]

* @param {Array} [seed] A set of elements to match against

*/

select = Sizzle.select = function( selector, context, results, seed ) {

var i, tokens, token, type, find,

compiled = typeof selector === "function" && selector,

match = !seed && tokenize( (selector = compiled.selector ||

selector) );

...

每个方法都应该有详细的注释

Page 12: Maintainable Javascript

switch(mode) {

case 1: // to B

changeTo('B');

break;

case 2: // mix A and B

mixWith('A', 'B');

break;

case 3: // to A

changeTo('A');

break;

case 4: // mix B and C

mixWith('B', 'C')

break;

}

较难理解的代码

Page 13: Maintainable Javascript

命名

● 用更易理解的名字给变量(Variables)/函数(Functions)命名

○ 不要在意长度

https://www.allacronyms.com/

Page 14: Maintainable Javascript

命名

● 用更易理解的名字给变量(Variables)/函数(Functions)命名

○ 不要在意长度

● 变量应该是名词

● 函数应该以动词开头(如 getName() )○ 返回布尔类型的函数应该以“is”或“has”开头(如 isVaild(), hasItem() )

● 避免使用无意义的名字,如 foo,bar,temp

Page 15: Maintainable Javascript

if (wl && wl.length) {

for (var i = 0; i < wl.length; i++) {

p = wl[i];

if (s.hasOwnProperty(p)) {

r[p] = s[p];

}

}

}

Page 16: Maintainable Javascript

那些年,我们踩过的坑

Do we really know JS ?

Page 17: Maintainable Javascript

var result = 1;

result == 1 // true

result == '1' // true

不要过于相信 == 的兼容性

[] == []

var a = [0];

if ([0]) {

console.log(a == true);

} else {

console.log("go here");

}

Page 18: Maintainable Javascript

0.2 - 0.1 === 0.1

0.8 - 0.6 === 0.2

注意浮点数的运算

// true

// false

Page 19: Maintainable Javascript

<button id="btn1">Click btn1</button>

<button id="btn2">Click btn2</button>

<button id="btn3">Click btn3</button>

for(var i = 1; i <= 3; i++){

$.on('#btn'+i, 'click', function(){

console.log('You are clicking:', 'btn' + i);

});

}

执行循环时,时刻注意作用域

// You are clicking: btn4

Page 20: Maintainable Javascript

<button id="btn1">Click btn1</button>

<button id="btn2">Click btn2</button>

<button id="btn3">Click btn3</button>

for(var i = 1; i <= 3; i++){

$.on('#btn'+i, 'click', function(){

console.log('You are clicking:', 'btn' + i);

});

}

执行循环时,时刻注意作用域

// You are clicking: btn4

http://latentflip.com/loupe

Page 21: Maintainable Javascript

<button id="btn1">Click btn1</button>

<button id="btn2">Click btn2</button>

<button id="btn3">Click btn3</button>

var handleClick = function(id) {

$.on('#'+id, 'click', function(){

console.log('You are clicking:', id);

});

}

for(var i = 1; i <= 3; i++){

handleClick('btn'+i);

}

执行循环时,时刻注意作用域

Page 22: Maintainable Javascript

http://ejohn.org/apps/learn/

Page 24: Maintainable Javascript

高效性

Page 25: Maintainable Javascript

编写高效的Javascript

● JSON比XML更快

● 高效地使用数组

● 尽量减少内存的占用

● 使用模版

Page 26: Maintainable Javascript

JSON比XML更快

● 使用原生的JSON方法

var data = {a:'this is json data'};

var jsonStr = JSON.stringify(data);

var jsonData = JSON.parse(jsonStr);

Page 27: Maintainable Javascript

数组内部运作

var a = new Array();

a[0] = 1;

a[1] = 2.3;

a[2] = 'str';

Type: Int Array

Page 28: Maintainable Javascript

数组内部运作

var a = new Array();

a[0] = 1;

a[1] = 2.3;

a[2] = 'str';

Type: Int Array

Type: Int Array 1

Page 29: Maintainable Javascript

数组内部运作

var a = new Array();

a[0] = 1;

a[1] = 2.3;

a[2] = 'str';

Type: Int Array

Type: Int Array 1

Type: Float Array 1 2.3

Page 30: Maintainable Javascript

数组内部运作

var a = new Array();

a[0] = 1;

a[1] = 2.3;

a[2] = 'str';

Type: Int Array

Type: Int Array 1

Type: Float Array 1 2.3

Type: Var Array 1 2.3 ‘str’

Page 31: Maintainable Javascript

给数组预分配长度

var a = new Array();

for (var i = 0; i < 100; i++){

a.push(i + 2);

}

SLOW

var a = new Array(100);

for (var i = 0; i < 100; i++){

a[i] = i + 2;

}

FAST

Page 32: Maintainable Javascript

混合类型的数组,预定义类型

var a = new Array(100);

for (var i = 0; i < a.length; i++){

a[i] = i;

}

...

// 数组操作

...

a[99] = 'str';

SLOW

var a = new Array(100);

a[0] = 'hint';

for (var i = 0; i < a.length; i++){

a[i] = i;

}

...

// 数组操作

...

a[99] = 'str';

FAST

Page 33: Maintainable Javascript

Delete会迫使引擎进行类型转变(变慢)

var a = new Array(100);

...

for (var i = 0; i < 100; i++){

a[i] = [1,2,3];

}

...

delete a[23];

SLOW

var a = new Array(100);

...

for (var i = 0; i < 100; i++){

a[i] = [1,2,3];

}

...

a[23] = 0;

FAST

Page 34: Maintainable Javascript

缓存数组长度,避免重复性地访问属性

var a = new Array(100);

var total = 0;

for (var item in a){

total += item;

}

a.forEach(function(item){

total += item;

});

for (var i = 0; i < a.length; i++){

total += a[i];

}

SLOW

var a = new Array(100);

var total = 0;

var cachedLength = a.length;

for (var i = 0; i < cachedLength; i++){

total += a[i];

}

FAST

https://jsperf.com/for-vs-foreach/37

Page 35: Maintainable Javascript

缓存数组长度,避免重复性地访问属性

var a = new Array(100);

var total = 0;

for (var item in a){

total += item;

}

a.forEach(function(item){

total += item;

});

for (var i = 0; i < a.length; i++){

total += a[i];

}

SLOW

var a = new Array(100);

var total = 0;

var cachedLength = a.length;

for (var i = 0; i < cachedLength; i++){

total += a[i];

}

FAST

Page 36: Maintainable Javascript

高效地使用数组(Best Practices)

● 给数组预分配长度

● 混合类型的数组,预定义类型

● Delete会迫使引擎进行类型转变(变慢)

● 缓存数组长度,避免重复性地访问属性

Page 37: Maintainable Javascript

哪些条件下,会影响内存的分配?

● 直接或间接地使用 new ○ 给对象预留内存

● Runtime下强制执行GC(垃圾回收)

● 每次定义/引用对象的时候

Page 38: Maintainable Javascript

什么是垃圾回收(Garbage Collection)?

● 当内存池已满,已经无法再给新对象分配内存时,会把之前使用过的且再也

没有被引用的对象清空,腾出内存供新对象使用。

Page 39: Maintainable Javascript

V8引擎垃圾回收(GC)机制

Page 40: Maintainable Javascript

V8引擎垃圾回收(GC)机制

● Young Generation有更高的被回收率

Page 41: Maintainable Javascript

V8引擎垃圾回收(GC)机制

To Space

From Space GC时使用

Page 42: Maintainable Javascript

V8引擎垃圾回收(GC)机制

To Space

From Space GC时使用

Page 43: Maintainable Javascript

V8引擎垃圾回收(GC)机制

未被分配的内存

From Space GC时使用

A

分配给对象A

Page 44: Maintainable Javascript

V8引擎垃圾回收(GC)机制

未被分配的内存

From Space GC时使用

A

分配给对象B

B

Page 45: Maintainable Javascript

V8引擎垃圾回收(GC)机制

未被分配的内存

From Space GC时使用

A

分配给对象C

B C

Page 46: Maintainable Javascript

V8引擎垃圾回收(GC)机制

未被分配的内存

From Space GC时使用

A B C D

不够用了!

Page 47: Maintainable Javascript

V8引擎垃圾回收(GC)机制

未被分配的内存

From Space GC时使用

A B C

GC开始!

程序暂停!

Page 48: Maintainable Javascript

V8引擎垃圾回收(GC)机制

To Space

未被分配的内存A B C

空间被交换!

Page 49: Maintainable Javascript

V8引擎垃圾回收(GC)机制

To Space

未被分配的内存A B C

正在使用/被引用的对象

Page 50: Maintainable Javascript

V8引擎垃圾回收(GC)机制

To Space

未被分配的内存A B C

正在使用/被引用的对象

Page 51: Maintainable Javascript

V8引擎垃圾回收(GC)机制

To Space

未被分配的内存A B C

正在使用/被引用的对象

复制

Page 52: Maintainable Javascript

V8引擎垃圾回收(GC)机制

未被分配的内存A B C

正在使用/被引用的对象

未被分配的内存A C

Page 53: Maintainable Javascript

V8引擎垃圾回收(GC)机制

From Space

未被分配的内存A C

Page 54: Maintainable Javascript

V8引擎垃圾回收(GC)机制

From Space

未被分配的内存A C D

分配给对象D

Page 55: Maintainable Javascript

每次垃圾回收都会暂停程序执行(卡顿/掉帧)

Page 56: Maintainable Javascript

内存泄漏

Page 57: Maintainable Javascript

内存泄漏

16ms!JS / CSS > 计算样式 > 布局 > 绘制 > 渲染层合并

Page 58: Maintainable Javascript

内存泄漏

Page 59: Maintainable Javascript

Slow Object vs Fast Object

function SlowPurchase(price) {

this.price = price;

this.total = 0;

this.x = 1;

}

var slow = new SlowPurchase(25);

// x没用,我删掉它

delete slow.x;

SLOW

function FastPurchase(price) {

this.price = price;

this.total = 0;

this.x = 1;

}

var fast = new FastPurchase(25);

FAST

Page 60: Maintainable Javascript

Slow Object会占用更多的内存

Page 61: Maintainable Javascript

DOM泄漏 var treeRef = $('#tree');

var leafRef = $('#leaf');

$('body').remove(treeRef);

// 此时 #tree 并没有被回收,

// 因为还有 treeRef 对象在引用

// 好,那就清空它

treeRef = null;

// 此时 #tree 还是没有被回收,

// 因为还有 leafRef 对象在间接引用

//(leafRef.parentNode)

leafRef = null;

// 好了,这次 #tree 可以被回收了

Page 62: Maintainable Javascript

“Premature optimization is the root of all evil”

- Donald Knuth

该优化的时候再优化

Page 63: Maintainable Javascript

内存监测工具

● performance.memory● 任务管理器

● Chrome Dev Tools

https://speakerdeck.com/addyosmani/javascript-memory-management-masterclass

Page 66: Maintainable Javascript

模版的发展var data = {

"result": [

{

"title": "Strawberry"

},{

"title": "Vanilla"

},{

"title": "Ice"

}

]

};

var template = '<ul>';

for (var i = 0; i < data.result; i++) {

template += '<li id="item' + i +

'"><strong>Title:</strong>' +

data.result[i].title +

'</li>';

}

template += '</ul>';

$('#container').html(template);

字符串拼接

var data = {

"result": [

{

"title": "Strawberry"

},{

"title": "Vanilla"

},{

"title": "Ice"

}

]

};

<!-- html -->

<script type="text/mustache-template" id="mustache">

<ul>

{{#result}}

<li><strong>Title:</strong> {{title}}</li>

{{/result}}

</ul>

</script>

// Javascript

var template = $('#mustache').html()

var html = Mustache.to_html(template, data);

$('#container').html(html);

模版引擎

Page 67: Maintainable Javascript

数据绑定

Page 68: Maintainable Javascript

数据绑定(Vue.js)

// javascript

var data = {

"result": [

{

"title": "Strawberry"

},{

"title": "Vanilla"

},{

"title": "Ice"

}

]

};

var app = new Vue({

el: '#container',

data: data.result

});

<!-- html -->

<div id="container">

<ul>

<li v-for="item in data">

<strong>Title:</strong>

{{item.title}}

</li>

</ul>

</div>

Page 69: Maintainable Javascript

资源链接

JS性能比较:

https://jsperf.com/

V8引擎工作原理呈现工具:

http://mrale.ph/irhydra/2/

Event Loop原理呈现工具:

http://latentflip.com/loupe

Practical Performance Tips to Make Your HTML JavaScript Faster(微软教程):

https://www.youtube.com/watch?v=dk75fqFXwCE&list=PLMywOXqBTbMVgzv_oGGmdRTAPl2URqopE&index=8

Maintainable Javascript:https://www.youtube.com/watch?v=3MejbqcMC08&list=PLMywOXqBTbMVgzv_oGGmdRTAPl2URqopE&index=7

Page 70: Maintainable Javascript

Thanks!