潜力无限的编程语言Javascript

127
淘宝北京研发中心 2012-04 潜力无限的编程语言 Javascript 诗鸣 – F2E@Taobao

description

 

Transcript of 潜力无限的编程语言Javascript

Page 1: 潜力无限的编程语言Javascript

淘宝北京研发中心 2012-04

潜力无限的编程语言 Javascript

诗鸣 – F2E@Taobao

Page 2: 潜力无限的编程语言Javascript

• Who�Are�We?淘宝前端开发工程师http://ued.taobao.com

Page 3: 潜力无限的编程语言Javascript

• Javascript语言• 引擎• Web性能

Topic

Page 4: 潜力无限的编程语言Javascript

• Javascript特性• 作用域、作用域链、闭包• 函数式编程

Javascript语言

Page 5: 潜力无限的编程语言Javascript

Javascript语言特性

Page 6: 潜力无限的编程语言Javascript

Javascript语言——特性

高阶函数:•将函数作为参数;•可以返回一个函数。

动态类型:• 晚绑定;• 可以赋给变量任意类型的值,并可随时更改类型。

灵活的对象模型:•JavaScript�的对象模型使用一种相对不常见的方式进行继承 —— 称为原型 ;•不是 Java�语言中更常见的基于类的对象模型。

演示者
演示文稿备注
动态类型:
Page 7: 潜力无限的编程语言Javascript

Javascript语言——特性

高阶函数-传递函数:

var woman = function () {alert('beauty');

}var man = function () {

alert('cool')}var swap = function () {

var temp = woman,woman = man,man = temp;

alert('交换成功')}

查看示例

演示者
演示文稿备注
高阶函数:可以将函数作为参数传递,可以将函数作为返回值
Page 8: 潜力无限的编程语言Javascript

Javascript语言——特性

动态类型:

var a = new Object();a.sex = ‘美女’;a.age = 21;a.say = function(){ return '帅哥你好~' };alert(a.sex);alert(a.age);alert(a.say());a.say = ‘从函数变成字符串’;alert(a.say)

可以赋给变量任意类型的值,并可随时更改类型

查看示例

演示者
演示文稿备注
在javascript中,我们可以给变量赋予任何类型的值,而无需提前声明,并且可以随时更改,在本例中,我们给变量赋值了字符串、整形、函数
Page 9: 潜力无限的编程语言Javascript

Javascript语言——特性

动态类型——晚绑定:

//先定义一个函数afunction a(){

alert(‘hello world!’)}

//在点击按钮时才执行<button onclick=“a()”>执行a</button>

查看示例

演示者
演示文稿备注
晚绑定(late binding)指的是编译器或解释程序在运行前,不知道对象的类型。使用晚绑定,无需检查对象的类型,只需检查对象是否支持属性和方法即可。ECMAScript 中的所有变量都采用晚绑定方法。这样就允许执行大量的对象操作,而无任何惩罚。这给我们编写代码带来很大的灵活性
Page 10: 潜力无限的编程语言Javascript

Javascript语言——特性

对象模型——创建一个构造函数:

//创建一个人并给Ta赋予一些属性var person = function () {

this.name = '多多';this.say = function () {

return ‘亲~‘};

}//基于person的原型定义一个新对象womanvar woman = new person();alert('这位美女的名字是'+woman.name+',她对大家说:“'+woman.say+'”');

查看示例

演示者
演示文稿备注
到目前为止,大家应该对javascript有一个正确的认识了,我们可以使用js的对象模型创建复杂并且交互良好的面向对象的应用。 我们基于person创建一个woman(女人)的实例,这样,woman就可以使用person中的属性和函数,甚至重定义函数和属性。
Page 11: 潜力无限的编程语言Javascript

Javascript语言——特性

对象模型——通过原型继承:

var person = function () {this.name = '多多';this.say = function () {return

'Remember'};}var woman = function () {

this.say = function () {return '亲们~请多关照'

}}woman.prototype = new person();var x = new woman();alert(‘这位美女的名字是’+x.name+‘;美女对大家说:“’+x.say()+'”');

例查看示例

演示者
演示文稿备注
在这个例子中,我们创建了一个woman的原型,此原型基于person,woman重新定义了say的方法,但没有对name方法做任何改动,然后,我们将woman的原型设置成person。 Javascript优秀的灵活性让我们体会到了一些高阶语言的强大功能。那么接下来就让我们继续深入的了解一下这个东东。
Page 12: 潜力无限的编程语言Javascript

作用域、作用域链、闭包

Page 13: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

作用域 (Scope)

作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在JavaScript中,变量的作用域有全局作用域和局部作用域两种。

Page 14: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

全局作用域(Global�Scope)在代码中任何地方都能访问到的对象拥有全局作用域,以下几种情形拥有全局作用域:

Page 15: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

全局作用域① 外层函数和在 外层函数外面定义的变量拥有全局作用域:

var a = 'global';function b() {

var c = 'local';function d() {alert(c);}d();

}alert(a); //globalalert(c); //not definedb(); //locald(); //no defined

查看示例

Page 16: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

全局作用域②所有末定义直接赋值的变量自动声明为拥有全局作用域:

function a() {var b = 'local';c = 'global';

}a();alert(c); //globalalert(b); //not�defined

变量c拥有全局作用域,而b在函数外部无法访问到。

查看示例

Page 17: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

全局作用域③所有window对象的属性拥有全局作用域:

一般情况下,window对象的内置属性都都拥有全局作用域,例如window.namewindow.locationwindow.top

……

Page 18: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

局部作用域(Local�Scope)和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到, 常见的例如函数内部,所以也被称为函数作用域,例如下列代码中的b和函数c都只拥有局部作用域。

例 function a() {var b = 'local';function c() {alert(b);}c();

}alert(b); //not definedc(); //not defined

Page 19: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

作用域链(Scope�Chain)

在JavaScript中,函数也是对象,函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。

实际上,JavaScript全家都是对象。

Page 20: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

function a(x, y) {var b = x + y;return b;

}

当一个函数创建后,它的作用域链会被创建此函数的作用域中可访问的数据对象填充。

a[[Scope]]

Scope chain

0

Global object

this window

window (object)

document (object)

a function

在函数a创建时,它的作用域链中会填入一个全局对象,该全局对象包含了所有全局变量

Page 21: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

执行此函数时会创建一个称为“运行期上下文(execution�context)”的内部对象,运行期上下文定义了函数执行时的环境。每个运行期上下文都有自己的作用域链,用于标识符解析,当运行期上下文被创建时,它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象。

Page 22: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

Var total = a(5, 10)

var total=a(5,10)Execution�context

[[Scope]]

Scope chain

0

1Global object

this window

window (object)

document (object)

a (function)

total undefined

Activation object

this window

arguments [5,10]

x 5

y 10

b undefined

function a(x, y) {var b = x + y;return b;

}

演示者
演示文稿备注
这些值按照它们出现在函数中的顺序被复制到运行期上下文的作用域链中。它们共同组成了一个新的对象,叫“活动对象(activation object)”,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁。新的作用域链如本图所示:
Page 23: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

在函数的运行过程中,每遇到一个变量,都会经历一次标示符解析过程以决定从哪里获取或存储数据。

该过程搜索运行期上下文的作用域链,查找同名的标示符;搜索过程从作用域链顶部开始,也就是当前运行函数的活动对

象;如果找到,就使用这个标示符,反之继续搜索作用域链中的下

一个对象;搜索会持续进行,直到标示符被找到,或者没有可用于搜索的

对象为止(返回undefined);这个搜索过程会消耗性能;

如果名字相同的两个变量存在于作用域链的不同部分,那么标示符就是遍历作用域链时最先找到的那个。

Page 24: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

var a = ‘set1’function foo() {

a = ‘set2’;return a

}

alert(foo());

标示符解析

var a = ‘set1’function foo(){

b = ‘set2’return a

}

alert(foo());

查看示例

Page 25: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

如何从函数外部读取局部变量?

例 function a() {var b = 999;alert(c);function d() {

var c= 1;alert(b);

}}

演示者
演示文稿备注
在上面的代码中,函数d就被包括在函数a内部,这时a内部的所有局部变量,对d都是可见的。但是反过来就不行,d内部的局部变量,对a就是不可见的。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
Page 26: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

如何从外部读取局部变量?

例 function a() {var b = 999;function d() {alert(b);}return d;

}

Var foobar = a();foobar(); //999

演示者
演示文稿备注
既然d可以读取a中的局部变量,那么只要把d作为返回值,我们不就可以在a外部读取它的内部变量了吗!这种方式其实就是……
Page 27: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

闭包是 What?

演示者
演示文稿备注
上一节代码中的c函数,就是闭包。
Page 28: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

闭包是函数和执行它的作用域组成的综合体——《JavaScript权威指南》

闭包就是一种在函数内访问和操作外部变量的方式

所有的函数都是闭包

函数可以访问它被创建时的上下文环境,称为闭包——《JavaScript语言精粹》

内部函数比它的外部函数具有更长的生命周期

演示者
演示文稿备注
闭包的各种解释
Page 29: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

更简单的定义——闭包就是能够读取其他函数内部变量的函数。

由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

Page 30: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

查看示例

for(var i = 0;i<elements.length;i++){elements[i].onclick = function(){

alert(i);};

}

演示者
演示文稿备注
循环每次运行都会给i重新复制,所以,当点击elements[i]的时候,i已经是最终的结果了
Page 31: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

for(var i = 0;i<elements.length;i++){(function(n){elements[n].onclick = function(){alert(n);

});})(i);

}

查看示例

演示者
演示文稿备注
这里用到了匿名函数,每一次循环,就会定义并执行一个匿名函数,由于elements[n]的click事件一直在调用匿名函数的参数n,所以匿名函数不会被回收,因此,每一个i的值都会被对应的保存在内存中。
Page 32: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

闭包的应用场景

• 实现私有成员• 保护命名空间• 避免污染全局变量• 变量需要长期驻留在内存

闭包应用示例

Page 33: 潜力无限的编程语言Javascript

Javascript语言——作用域、作用域链、闭包

使用闭包的注意事项

•由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

•闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public�Method),把内部变量当作它的私有属性(private�value),这时一定要小心,不要随便改变父函数内部变量的值。

Page 34: 潜力无限的编程语言Javascript

函数式编程

Page 35: 潜力无限的编程语言Javascript

Javascript语言——函数式编程

什么是函数式编程:

函数式编程是种编程范型,它将电脑运算视为函数的计算。函数式编程的重点是函数的定义而不是像命令式编程那样强调状态机(state�machine)的实现。

——维基百科

演示者
演示文稿备注
也就是说,函数式编程只描述在程序输入上执行的操作,重点是捕捉 “是什么以及为什么”,而不是 “如何做”,我们只需知道一个函数能返回什么样的结果,然后将结果用于进一步的运算。
Page 36: 潜力无限的编程语言Javascript

Javascript语言——函数式编程

JavaScript中函数的特性:

•函数并不总是需要名称。•函数可以像其他值一样分配给变量。•函数表达式可以编写并放在括号中,留待以后应用。•函数可以作为参数传递给其他函数。

演示者
演示文稿备注
在我们之前讲到的高阶函数中,也提及到了这些特性
Page 37: 潜力无限的编程语言Javascript

Javascript语言——函数式编程

JavaScript中函数式编程的一些特性:

•函数是顶层对象•高阶函数•闭包•函数柯里化(Currying)•函数式代码风格

Page 38: 潜力无限的编程语言Javascript

Javascript语言——函数式编程

函数是顶层对象

•function是JavaScript中 基础的模块,本身为一种特殊对象(Object);•不依赖于任何其他的对象而可以独立存在;•一切皆是可传入function的值,连function本身也不例外。

Page 39: 潜力无限的编程语言Javascript

Javascript语言——函数式编程

高阶函数——对函数的进一步抽象

例 var myarr = [2, 5, 7, 3];var byAsc = function (x,y) { return x‐y; };var byDesc = function (x,y) { return y‐x; };myarr.sort(byAsc);alert(myarr); //2,3,5,7myarr.sort(byDesc);alert(myarr); //7,5,3,2

//Array对象的sort方法,需传入一比较函数

查看示例

演示者
演示文稿备注
我们之前讲到的高阶函数的特性——可以将函数作为参数传递
Page 40: 潜力无限的编程语言Javascript

Javascript语言——函数式编程

例 var myarr = [2, 5, 7, 3];myarr.sort(function (x, y) {

return x‐y;});

//或者直接用一个匿名函数:

高阶函数——对函数的进一步抽象

sort既是JS引擎自身提供的一个高阶函数。sort传入的比较函数(byAsc,�byDesc)是没有任何预先的假设的,sort是对整个排序方法的二阶抽象,因此称之为“高阶”函数。

查看示例

Page 41: 潜力无限的编程语言Javascript

Javascript语言——函数式编程

函数柯里化(Currying)

在计算机科学中,柯里化是把接受多个参数的函数变换成接受一个单一参数( 初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。——详见 维基百科

Page 42: 潜力无限的编程语言Javascript

Javascript语言——函数式编程

例 var adder = function(num){return function(y){

return num + y;}

}var inc = adder(1);var dec = adder(‐1);//inc, dec现在是两个新的函数,作用是将传入的参数值(+/‐)1alert(inc(99));//100alert(dec(101));//100alert(adder(100)(2));//102alert(adder(2)(100));//102

柯里化就是预先将函数的某些参数传入,得到一个简单的函数。但是预先传入的参数被保存在闭包中,因此会有一些奇特的特性。比如:

查看示例

演示者
演示文稿备注
这里的inc/dec两个变量事实上是两个新的函数,可以通过括号来调用,比如下例中的用法:
Page 43: 潜力无限的编程语言Javascript

Javascript语言——函数式编程

函数式代码风格——连续运算

例 //连续赋值var a = b = c = d = 1000;

//短路条件a = a || '';a && a++;

//三元表达式a>b ? a++ : a‐‐;

演示者
演示文稿备注
解释着三种示例
Page 44: 潜力无限的编程语言Javascript

Javascript语言——函数式编程

函数式代码风格——链式调用

例 KISSY.one('#foo').height('100px').width('100px').addClass('unstyle').click(function () {

alert('hello')});

演示者
演示文稿备注
链式调用的优点是代码简洁易读,减少了多次重复使用同一个变量。最常见的还是在jQuery库里面,当然,现在YUI3、KISSY都支持链式调用
Page 45: 潜力无限的编程语言Javascript

Javascript语言——函数式编程

使用函数式编程优点:

•函数内的运算对函数外无副作用•便于调试及单元测试•编写更加优美的回调•高内聚,低耦合的一种体现

Page 46: 潜力无限的编程语言Javascript

• 主流浏览器的JS引擎• 加载和执行

• 垃圾回收

Javascript引擎

Page 47: 潜力无限的编程语言Javascript

Javascript引擎——简介

JavaScript引擎是一个专门处理JavaScript脚本的软件程序,一般会附带在网页浏览器之中。

—— 引自 维基百科

Page 48: 潜力无限的编程语言Javascript

V8

Carakan

JaegerMonkey

Nitro

JScript

Page 49: 潜力无限的编程语言Javascript

Javascript引擎——主流浏览器的JS引擎

正是由于浏览器JS引擎的不同,导致Javascript的不兼容。

演示者
演示文稿备注
由于浏览器JS引擎的不同,所以它们对JS的解析都有自己的个性,这也是导致前端工程师比较苦逼的一个原因
Page 50: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

编译(compiled) 解释(interpreted)

从源码到可执行代码

演示者
演示文稿备注
Javascript从源码到可执行的代码,需要经历编译=》解析的过程,下面我们来具体看一下
Page 51: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

编译

(function foo(){alert(‘helloworld’);

})();

01001011101101…

Runtime.exec(‘helloworld.exe’)

source.js(源码)

helloworld.exe(二进制码)

运行时环境

编译

运行

演示者
演示文稿备注
程序的编译过程
Page 52: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

解释

(function foo(){alert(‘helloworld’);

})();

Runtime.exec(‘中间机器码’)

source.js(源码)

helloworld.exe(二进制码)

解释器执行伪代码

编译&运行

运行时环境

演示者
演示文稿备注
解释器执行代码
Page 53: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

解释

(function foo(){alert(‘helloworld’);

})();

Runtime.exec(‘中间机器码’)

JavaScript引擎编译&运行

运行时环境(浏览器)

演示者
演示文稿备注
Javascript解释代码
Page 54: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

JavaScript�是解释型语言

Page 55: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

JavaScript代码执行的过程

词法分析

语法分析

预编译

语法检查

运行

运行时

Page 56: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

执行”0=1=2”

在语法检查阶段报错这是一个语法错误程序没有开始运行

Page 57: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

执行”a=b=c”

通过了语法检查在运行时报错

程序已经开始运行

演示者
演示文稿备注
通过对报错信息的分析,我们可以准确的定位错误的原因
Page 58: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

词法分析

语法分析

预编译

语法检查

运行

运行时

1,将上下文中var申明的变量放入”栈”中并赋值为undefined

2,读入”定义”的函数

Page 59: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

alert(a); //会报错吗?

var a = 1;例

Page 60: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

alert(a);var a = 1;

扫描整段代码,将a放入当前上下文的栈中,赋值为undefined

在栈中找到a并得到值undefined弹出”undefined”

将a赋值为1

局部变量的预编译

Page 61: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

a();function a(){alert(‘Tom’);

}var a = function(){alert(‘Jim’);

};a();

2,预编译读入a的定义

1,变量a入栈

函数的预编译

Page 62: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

a();function a(){alert(‘Tom’);

}var a = function(){alert(‘Jim’);

};a();

执行a(),弹出Tom

a被重新赋值

执行a(),弹出Jim

编译后的运行

Page 63: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

下面代码的运行结果?

Page 64: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

a();function a(){

alert(1);}a();function a(){

alert(2);}a();var a = function(){

alert(3);};a();

题 //2

//2

//2

//3

Page 65: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

常见问题

Page 66: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

//a未声明时报错,不推荐

alert(a === undefined);

//推荐alert(typeof a === ‘undefined’);

判断变量存在

演示者
演示文稿备注
我们习惯的以为a不存在就是undefined,但是,如果a未被声明过,那就会报错! 所以,最保险的用法就是使用typeof来判断变量是否存在,typeof的返回值是字符串,所以应该用字符串来比较 Typeof的返回结果有:“undefined, object,string,number,boolean,function”
Page 67: 潜力无限的编程语言Javascript

Javascript引擎——加载和执行

function(){alert(a); //显示undefined,不报错if(false){

var a = 1; //不会执行到,亦被声明}

}()

函数执行前,函数内部变量均被声明

Page 68: 潜力无限的编程语言Javascript

Javascript引擎——垃圾回收

JavaScript不需要手动地释放内存,它使用一种自动垃圾回收机制(garbage�collection)。当一个对象无用的时候,即程序中无变量引用这个对象时,就会从内存中释放掉这个变量。

Page 69: 潜力无限的编程语言Javascript

Javascript引擎——垃圾回收

function a() {this.text = 'a的弹窗'

}function b() {

this.text = 'b的弹窗'}function c() {

var x = new a();y = new b();return y;

}c();alert(y.text)

演示者
演示文稿备注
执行完C后,a会被回收,而b因为赋值给全局变量y,而被认为属于引用状态,GC不会回收它,所以这是个时候再alert(y.text)还是会有内容
Page 70: 潜力无限的编程语言Javascript

Javascript引擎——垃圾回收

闭包和垃圾回收

演示者
演示文稿备注
执行完C后,a会被回收,而b因为赋值给全局变量y,而被认为属于引用状态,GC不会回收它,所以这是个时候再alert(y.text)还是会有内容
Page 71: 潜力无限的编程语言Javascript

Javascript引擎——垃圾回收

function a() {var i = 0;function b() {

i++;alert(i)

}return b

}var c = a();c();c();c();

//�1//�2//�3

演示者
演示文稿备注
通常情况,a在执行完后,应该被GC回收,之后每次再运行C,会重新执行a,alert(i)的值应该是0。 原因,由于闭包的原因,i会一直存在于b的作用域链,导致不会被GC回收。
Page 72: 潜力无限的编程语言Javascript

• 快速响应的用户界面

• DOM编程

• Ajax性能

Web性能

Page 73: 潜力无限的编程语言Javascript

快速响应的用户界面

Page 74: 潜力无限的编程语言Javascript

Js执行和浏览器渲染

Web性能——快速响应的用户界面

Page 75: 潜力无限的编程语言Javascript

<!DOCTYPE HTML><html lang="zh">

<head>head</head><body>

<div id=“J”><script>$.write(‘helloworld’);</script>

</div>…</body></html>

渲染出Script�节点

document

head

body

div#J

script

浏览器暂停渲染HTML将script交由js引擎编译执行

Web性能——快速响应的用户界面

Page 76: 潜力无限的编程语言Javascript

<!DOCTYPE HTML><html lang="zh">

<head>head</head><body>

<div id=“J”><script>$.write(‘helloworld’);</script>

</div>…</body></html> Js引擎执行代码段结束

将渲染主动权交给浏览器继续渲染HTML

document

head

body

div#J

script

textNode

Js引擎创建了textNode

Web性能——快速响应的用户界面

Page 77: 潜力无限的编程语言Javascript

阻塞:

Js的执行会中断HTML的渲染

Web性能——快速响应的用户界面

Page 78: 潜力无限的编程语言Javascript

单线程的UI渲染

Web性能——快速响应的用户界面

Page 79: 潜力无限的编程语言Javascript

TimeUI Rendering Thread

DOM

1,构建出DOM

2,UI update

Page 80: 潜力无限的编程语言Javascript

TimeUI Rendering Thread

RenderUI

DOM

渲染出此时的Dom

Page 81: 潜力无限的编程语言Javascript

TimeUI Rendering Thread

RenderUI exec JS

DOM

3,JS脚本新增了DOM节点

Page 82: 潜力无限的编程语言Javascript

TimeUI Rendering Thread

RenderUI exec JS RenderUI

DOM

4,UI update

Page 83: 潜力无限的编程语言Javascript

避免阻塞:同样性能攸关的大事

(异步执行JavaScript)

Web性能——快速响应的用户界面

Page 84: 潜力无限的编程语言Javascript

Web性能——快速响应的用户界面…<div id=“J”><script>setTimeout(function(){

$.write(‘helloworld’);},100);</script>

</div><div>doc</div></body></html> Js引擎只启动了定时器,没有”write”操作

浏览器可以很快获得DOM渲染权,继续渲染HTML

body

div#J

script

Js引擎开启了定时器

Page 85: 潜力无限的编程语言Javascript

Web性能——快速响应的用户界面

…<div id=“J”><script>setTimeout(function(){

$.write(‘helloworld’);},100);</script>

</div><div>doc</div></body></html>

body

div#J

script

浏览器继续渲染html

div

Page 86: 潜力无限的编程语言Javascript

Web性能——快速响应的用户界面…<div id=“J”><script>setTimeout(function(){

$.write(‘helloworld’);},100);</script>

</div><div>doc</div></body></html>

body

div#J

script

定时器到时,插入domdiv

textNode

100ms

从定时器开启,到write节点完成中间的HTML渲染没有中断

Page 87: 潜力无限的编程语言Javascript

Web性能——快速响应的用户界面

…<div id=“J”><script>setTimeout(function(){

while(true){$.write(‘helloworld’);

}},100);</script>

</div>…

异步也不是万能的

Js中低效的Dom操作依然会阻断浏览器的渲染,让浏览器看起来像“冷冻”住

body

div#J

script

div

textNode

100ms

演示者
演示文稿备注
通过上面的讲解,我们了解了浏览器的渲染原理,那么我们可以在实际工作当中,尽可能的避免阻塞,比如说,把js脚本放在页面的底部执行,或者让js在dom加载完成后执行,都可以避免浏览器渲染停滞。 那么,针对现在现代的浏览器,我们更可以运用一些更好的方法,比如……
Page 88: 潜力无限的编程语言Javascript

Web性能——快速响应的用户界面

你有没有想过?

•在运行大型复杂的JavaScript脚本的时候不会发生浏览器假死?

•JavaScript可以在后台运行?

•JavaScript函数甚至可以在多个进程中同时运行?

Page 89: 潜力无限的编程语言Javascript

Web性能——快速响应的用户界面

Web�Workers

演示者
演示文稿备注
Web worker就可以实现我们的梦想
Page 90: 潜力无限的编程语言Javascript

Web性能——快速响应的用户界面

•运行于浏览器UI线程之外•已被firefox、chrome、safari原生支持•Worker之间不会互相影响

Web�Workers的特点

Page 91: 潜力无限的编程语言Javascript

Web性能——快速响应的用户界面

Worker运行环境由以下部分组成:

navigator对象,appName\appVersion\user�Agent\platform

Location对象 ==�window.location,但只读

Self对象,指向全局worker对象

importScripts()对象,加载外部JS文件

所有ECMAScript对象,如:Object/Array/Date�等

XMLHttpRequest构造器

setTimeout()和setInterval()方法

close()方法,立刻停止Worker运行。

Page 92: 潜力无限的编程语言Javascript

Web性能——快速响应的用户界面

与Worker通信

消息系统是网页和Worker通信的唯一途径

postMessage()只能传递:•字符串、数字、布尔值、null和undefined•Object 和Array(目前safari只支持字符串)

Page 93: 潜力无限的编程语言Javascript

Web性能——快速响应的用户界面

与Worker通信

var worker = new Worker('worker.js');worker.onmessage = function(event){

alert(event.data);}worker.postMessage('1');

例 //页面中的事件接口

演示者
演示文稿备注
那么我们如何让页面与work通信呢? Worker与页面之间的通信就是依靠postMessage来传递数据,用onmessage来获取数据
Page 94: 潜力无限的编程语言Javascript

Web性能——快速响应的用户界面

与Worker通信

self.onmessage = function(event){var a;if(event.data === '1'){

a = 'result is 1';}if(event.data === '2'){

a = 'result is 2';}self.postMessage(a);

};

例 //worker运行代码(worker.js文件)

查看示例

Page 95: 潜力无限的编程语言Javascript

Web性能——快速响应的用户界面

Worker适用于处理

•编码/�解码大字符串(如:巨大的json)

•复杂数学运算(包括图像或视频处理)

•大数组排序

Page 96: 潜力无限的编程语言Javascript

DOM编程

• UI�Update• 通过DOM事件处理与用户的交互

演示者
演示文稿备注
我们通过这两个方面来讲一下DOM编程中的性能问题
Page 97: 潜力无限的编程语言Javascript

DOM为什么会慢?

访问和操作DOM是现代web应用的重要部分。但每次穿越链接ECMAScript和DOM两个岛屿之间的桥梁,都会被收取“过桥费”。因此我们要运用一些方法来减少DOM编程带来的性能损失。

演示者
演示文稿备注
浏览器中通常会把DOM和Javascript独立实现,比如在IE中,Javascript的实现名为Jscript,位于jscript.dll文件中;DOM的实现则存在另一个库中,名为mshtml.dll(内部称为Trident)。这对性能意味着什么?简单理解:两个相互独立的功能只要通过接口彼此连接,就会产生消耗
Page 98: 潜力无限的编程语言Javascript

Web性能——DOM编程

UI Update

• 重绘Repaint• 重排Reflow

演示者
演示文稿备注
首先,我们来了解一下浏览器的重绘与重排
Page 99: 潜力无限的编程语言Javascript

Web性能——DOM编程

Repaint:• 透明度更改• 文字颜色变化• 背景颜色变化• 背景图片替换

<div id=“J”><script>$(‘J’).css(‘color’,’red’);</script>

</div> 重绘Repaint

演示者
演示文稿备注
只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。 
Page 100: 潜力无限的编程语言Javascript

Web性能——DOM编程

Reflow:• 页面渲染过程中• Dom结构变化• 浏览器窗口大小改变• 布局变化

<div id=“J”><script>$(‘J’).append(‘<div>text</div>’);</script>

</div> Reflow

演示者
演示文稿备注
)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(其实我觉得叫重新布局更简单明了些)。每个页面至少需要一次回流,就是在页面第一次加载的时候。 
Page 101: 潜力无限的编程语言Javascript

Web性能——DOM编程

减少Reflow/paint:性能攸关的大事!

Page 102: 潜力无限的编程语言Javascript

Web性能——DOM编程

<div id=“J”><script>for(i=0;i<100;i++)

$(‘J’).append(‘<div>’+i+’</div>’);</script>

</div>Reflow * 100 !

不好的做法

Reflow了一百遍,一百遍!

Page 103: 潜力无限的编程语言Javascript

Web性能——DOM编程

TimeUI Rendering�Thread

RenderUI Run�js for�long�time RenderUI

DOM

UI�updateUI 没有反应…

Page 104: 潜力无限的编程语言Javascript

Web性能——DOM编程

<div id=“J”><script>var str = ‘’;for(i=0;i<100;i++)

str += ‘<div>’+i+’</div>’$(‘J’).append(str);</script>

</div>

好的做法

Reflow 1次

Page 105: 潜力无限的编程语言Javascript

Web性能——DOM编程

使用事件代理

1. 避免重复绑定

2. 减少事件绑定的处理时间

3. 减少内存占用

4. 对新插入的节点不用再次绑定

演示者
演示文稿备注
事件绑定通常发生在onload or DOMContentReady的时候,此时对富交互应用的网页都是一个拥堵时刻,时间绑定占用了处理时间,而且,浏览器需要跟踪每个事件处理器,而且并不是100%的按钮或链接都会被用户点击到,因此,有很多绑定工作都是没必要的
Page 106: 潜力无限的编程语言Javascript

Web性能——DOM编程

E.on(document, 'click', function(e){var el = e.target;switch (el.tagName.toLowerCase()){

case : 'a'//do somethingbreak

case : 'button'//do somethingbreak

defalut:......

}})

使用框架的事件代理(KISSY)

Page 107: 潜力无限的编程语言Javascript

Ajax性能

Page 108: 潜力无限的编程语言Javascript

Web性能——Ajax性能

•两种主流的请求方式

•两种发送数据技术

•数据格式

•Ajax性能指南

Page 109: 潜力无限的编程语言Javascript

两种主流的请求方式

•XMLHttpRequest(XHR)

•Dynamic�script�tag�insertion�动态脚本注入(JSON-P)

Web性能——Ajax性能

Page 110: 潜力无限的编程语言Javascript

提高XMLHttpRequest(XHR)性能

Web性能——Ajax性能

一.�通过监听readyState 提高性能

例 readyState == 0 //尚未加载readyState == 1 //正在加载readyState == 2 //加载完毕readyState == 3 //正在处理readyState == 4 //处理完毕

通过监听readyState值等于3,说明此时正在与服务器交互,响应信息还在传输中。这就是传说中的“流”(streaming),它是提升数据请求性能强大的工具

演示者
演示文稿备注
通过监听readyState值等于3,你可以与正在传输中的服务器响应进行交互,此时说明正在与服务器交互,响应信息还在传输中。这就是传说中的“流”(streaming),它是提升数据请求性能强大的工具
Page 111: 潜力无限的编程语言Javascript

Web性能——Ajax性能

提高XMLHttpRequest(XHR)性能

一.�通过监听readyState 提高性能

例 req.onreadystatechange = function(){if(req.readyState === 3){

//接收到部分信息,但不是所有var dataSoFar = req.responseText;...do someting

}else if(req.readyState === 4){

//所有信息接收完毕var data = req.responseText;...do someting

}}

Page 112: 潜力无限的编程语言Javascript

提高XMLHttpRequest(XHR)性能

Web性能——Ajax性能

一.�通过监听Http状态码 status 提高性能

例 status == 200 //请求成功status == 202 //请求被接受但处理未完成status == 400 //错误请求status == 404 //请求资源未找到status == 500 //内部服务器错误

如果遇到比较大的数据时,监听status,客户端可提前响应,避免用户等待解析数据的时间

演示者
演示文稿备注
这是提升用户体验的比较好的办法
Page 113: 潜力无限的编程语言Javascript

Web性能——Ajax性能

两种发送数据技术

•XHR(XMLHttpRequest)•信标(Beacons)

Page 114: 潜力无限的编程语言Javascript

Web性能——Ajax性能

XMLHttpRequest

•使用GET或POST方式

•GET只发送 一个数据包,速度更快

•POST(头信息、正文)两个数据包,更适合发送大量的数据

•IE对URL长度有限制(2083字节)

Page 115: 潜力无限的编程语言Javascript

Web性能——Ajax性能

信标(Beacons)

•使用JS创建一个新Image对象,并把src设置为服务器脚本的URL

•简单、性能消耗小,长度被限制,且无法发送POST数据

•监听image的load事件来获知服务器响应

例 var url = '/a.php';var params = ['step=2', 'time=1238027314'];var beacon = new Image();beacon.src = url + '?'+ params.join('&');

演示者
演示文稿备注
例,使用width属性来定义状态,1:成功, 2:失败,然后做相应的处理
Page 116: 潜力无限的编程语言Javascript

Web性能——Ajax性能

信标(Beacons)

例 //使用信标处理服务器返回状态beacon.onload = function () {

if(this.width == 1){//成功

}else if(this.width == 2){

//失败}

}

演示者
演示文稿备注
信标是向服务器回传数据最快最有效的方式,服务器不用发送任何响应正文,唯一的缺点是我们能接收到的响应类型是有限的。如果你需要发挥大量的数据给客户端,请使用XHR,如果只发送数据到服务器(可能返回极少的信息),那么请使用信标。
Page 117: 潜力无限的编程语言Javascript

Web性能——Ajax性能

数据格式

•XML•JSON•JSON-P•HTML•自定义

Page 118: 潜力无限的编程语言Javascript

Web性能——Ajax性能

XML

优点:

•极佳的通用性、格式严格、易验证

缺点:

•极冗长.每个单独的数据片断都依赖大量结构,所以有效数据的比

例非常低.

•语法模糊,当把一个数据结构转化为XML时,可以把对象参数放到

对象元素的属性中,也可放在独立的子元素中,可以使用描述清晰的

长标签名,也可以使用高效但难以辨认的短标签名.

•语法的解析过程含混,必须提前知道XML响应的布局

Page 119: 潜力无限的编程语言Javascript

Web性能——Ajax性能

JSON

•JSON是一种使用JS对象和数组直接量编写的轻量级且易于解析

的数据格式.

•可以直接使用eval()来解析JSON字符串.但是在代码中使用eval是

很危险的,特别是用它执行第三方的json数据.

•尽可能使用JSON.parse()方法解析字符串本身.该以捕获JSON中

的词法错误,并允许传入一个函数用来过滤或转换解析结果

Page 120: 潜力无限的编程语言Javascript

Web性能——Ajax性能

JSON-P

•使用动态脚本注入获取,把数据当做可执行javascript解析

•解析速度快,可跨域

•涉及敏感数据时不应该用它

Page 121: 潜力无限的编程语言Javascript

Web性能——Ajax性能

HTML

•服务器端生成HTML返回给客户端,JS使用innerHTML属性把它插

入页面相应的位置.

•在客户端的瓶颈是CPU而不是带宽时才使用此技术.

Page 122: 潜力无限的编程语言Javascript

Web性能——Ajax性能

自定义格式

•用数据中不会存在的单字符做分隔.解析时只需要用split()传入字

符串或正则表达式进行.

•var rows=req.responseText.split(/\u0001/);

//正则表达式,IE中的split()会忽略紧挨着的两个分隔符中的第二个

分隔符.\u0001是Unicode表示法.

•var rows=req.responseText.split("\u0001");

//字符串,更为保险

•对于非常大的数据集,它是 快的格式.需要在很短的时间内向客

户端传送大量数据时可以考虑使用此格式.

Page 123: 潜力无限的编程语言Javascript

Web性能——Ajax性能

Ajax性能指南

缓存数据快的ajax请求就是没有请求,有两种方法可以避免

发送不必要的请求:

1. 在服务端,设置HTTP头信息以确保你的响应会被浏览器缓存(使用简单,好维护)

2. 在客户端,把获取到的信息存储到本地,从而避免再次请求。(给你 大的控制权)

Page 124: 潜力无限的编程语言Javascript

Web性能——Ajax性能

1. 设置HTTP头信息

如果希望ajax响应能被浏览器缓存,必须使用GET方式发出请求.并且还需要在响应中告诉浏览器应该缓存多久.

一个Expires头信息格式如下:

Expires:Mon,28�Jul�2014�23:30:00�GMT

告诉浏览器缓存此响应到2014年7月。

Page 125: 潜力无限的编程语言Javascript

Web性能——Ajax性能

2.��本地数据存储

把数据从服务器接收后储存起来,把响应文本保存到一个对象中,以URL为键值作为索引.

例 var localCache = {url : req.responseText

}

每次发请求前,先检查url是否访问过,如果访问过,就从本地缓存中读取。

Page 126: 潜力无限的编程语言Javascript

高性能网站建设(进阶)指南,高性能JavaScripthttp://book.douban.com/subject/5362856/

Page 127: 潜力无限的编程语言Javascript