`
七七八八
  • 浏览: 44776 次
社区版块
存档分类
最新评论

[JavaScript]项目优化总结

阅读更多

前端时间对公司已有项目JavaScript代码进行优化,本文的是对优化工作的一个总结,拿出来与大家分享。当然我的优化方式可能并不是最优的,或者说有些不对的地方,请指教。

目录

JavaScript优化总结分为以下几点

模块化(类编程)

静态类

实例类

JavaScript压缩/合并

Uglifyjs安装

UglifyJS使用

JavaScript文件合并

文档生成

YUIDoc安装与使用

YUIDoc标签

公共类库说明

目录结构

自动合并、压缩脚本

文档说明

参考链接、进一步阅读

 

 

JavaScript优化总结分为以下几点

优化前后对比

优化前

优化后

代码混乱,同样功能的函数重复出现在多个地方。如果需要修改实现,需要找到所有的地方。牵一发而动全身

模块化,提取公共接口组织为库、结构清晰、方便代码重用、并且能够游戏防止变量污染问题。

JavaScript文件未压缩,size比较大加载消耗网络耗时,阻塞页面渲染

 

JavaScript公共库文件使用UglifyJS压缩:

n  Size比较小优化了网络加载时间

n  压缩混淆了代码,在一定程度上保护代码

使用时需要加载多个单独的JavaScript文件,增加了http请求数降低性能

对公共库合并压缩在减少size的同时,减少http请求数

缺乏文档(让后面的开发者对已有功能不清楚,这在一定程度上造成前面说的,同样功能的函数重复出现在多个地方)

公共库中每个类、函数、属性都有说明文档

 

 

l  模块化(类编程):代码清晰、有效防止变量污染问题、代码重用方便扩展等;

l  JavaScript压缩混淆:减少size优化加载时间,混淆保护代码;

l  JavaScript文件合并:减少http请求优化网络耗时提升性能;

l  生成文档:方便公共库的使用,查找接口方便。

 

对于静态类来说JavaScript实现比较简单,使用Object直接量就已经够用了;但是要创建实例化、可继承经典的类需要做一番工作。因为JavaScript基于原型的(prototype-based编程语言,并没有包含内置类的实现(它没有访问控制符,它没有定义类的关键字class,它没有支持继承的extend或冒号,它也没有用来支持虚函数的virtual等),但是我们通过JavaScript可以轻易地模拟出经典的类。

根据宝宝JS公共接口的特性,它们不需要实例化,所以优化使用了该方式。下面以PetConfigParser为例介绍下实现方式:

PetConfigParser

var PetConfigParser;

if (!PetConfigParser) {

    PetConfigParser = {};

}

 

(function () {

    //private 变量、函数

    /**

     宝宝所有配置字典,以【cate * 10000 + (lvl - 1) * 10 + dex - 1】为key

     * @attribute    petDic

     * @type {Object}

     * @private

     */

    var petDic = null;  //宝宝字典

 

    /**

     根据__pet_config构建一个Object字典,以catedexlvl组合作为key

     * @method buildPetDic

     * @private

     * @return {void}

     */

    function buildPetDic() {

        petDic = new Object();

        for (var item in __pet_config) {

            var lvl = parseInt(__pet_config[item]['lvl']);

            var dex = parseInt(__pet_config[item]['dex']);

            var cate = parseInt(__pet_config[item]['cate']);

            var key = cate * 10000 + (lvl - 1) * 10 + dex;

            petDic[key] = __pet_config[item];

        }

    }

 

    //public 接口

 

    /**

     根据宝宝id,读取__pet_config中对应宝宝的信息

     * @method getPetById

     * @param   {String/int} petId 宝宝id

     * @return  {Object} pet 宝宝的所有静态信息,如{id:"300003289", lvl:"1", dex:"2", price:"200", life:"2592000", cate:"3", name:"飞天小使等级1熟练2", intro:"", skill:"护身符", skill1_prob:"30", skill2_prob:"0"}

     */

    if (typeof PetConfigParser.getPetById !== 'function') {

        PetConfigParser.getPetById = function (petId) {

            var pet = ("undefined" == typeof (__pet_config)) ? null : __pet_config["pet_" + petId];

            return pet;

        }

}

})();

 

这种方式利用了JavaScript匿名函数来创建私有作用域,这些私有作用域只能在内部访问。总结上述过程分为以下几个步骤:

1)        定义一个全局的变量(var PetConfigParser),注意变量首字母大写与普通变量区别;

2)        然后创建一个匿名函数并运行( (function () {/*xxxx*/ })(); ),在匿名函数内部创建局部变量和函数,它们只能在当前作用域中被访问到;

3)        全局变量(var PetConfigParser)可以在任何地方访问到,在匿名函数内部操作PetConfigParser添加静态函数。

使用实例

$(function () {

        DialogManager.init();

        $('#showDialog').click(function () {

            DialogManager.show("#msgBoxTest", "#closeId");

            return false;

        });

 

        $('#cofirmBtn').click(function () {

            DialogManager.hide();

            return false;

        });

})

JavaScript实现经典的类,总结有三种方法:

n  构造函数方式;

n  原型方式;

n  构造函数+原型的混合方式

构造函数方式

构造函数用来初始化实例对象的属性和值。任何JavaScript函数都可以用作构造函数,构造函数必须使用new运算符作为前缀来创建新的实例。

构造函数方式

var Person = function (name) {

    this.name = name;

    this.sayName = function(){

        alert(this.name);

    };

}

 

//实例化

var tyler = new Person("tylerzhu");

var saylor = new Person("saylorzhu");

tyler.sayName();

saylor.sayName();

//检查实例

alert(tyler instanceof Person);

构造函数方式跟传统的面向对象语言是不是很相识!只不过是class关键字用function替换了。

注意:不要省略new否则Person(“tylerzhu”) //==>undefined。当使用new关键字来调用构造函数时,执行上下文(context)从全局对象(window)变成一个空的上下文,这个上下文代表了新生成的实例。因此,this关键子指向当前创建的实例。所以省略new时,没有进行上下文切换会在全局对象中查找name,没有找到而创建一个全局变量name返回undefined

原型方式

构造函数方式简单,但是存在一个浪费内存的问题。如上面的例子中实例化了两个对象tylersaylor,表面上好像没什么问题,但是实际上对于每一个实例对象,sayName()方法都是一模一样的内容,每一次生成一个实例,都必须为重复的内容申请内容。

alert(tyler. sayName == saylor. sayName) 输出false!!!

Javascript中每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例共享

原型方式

var Person = function (name) {

    Person.prototype = name;

    Person.prototype.sayName = function(){

        alert(this.name);

    }

}

 

//实例化

var tyler = new Person("tylerzhu");

var saylor = new Person("saylorzhu");

tyler.sayName();

saylor.sayName();

 

//检查实例

alert(tyler instanceof Person);

这时tylersaylor实例的sayName方法,都是同一个内存地址(指向prototype对象),因此原型方法更节省内存。

但是看tyler.sayName();saylor.sayName();两者输出,会看出问题 —— 它们都输出“saylorzhu”。因为原型所有属性都共享,只要一个实例改变其他的都会跟着改变,所以实例化对象saylor覆盖了tyler

 

构造函数+原型的混合方式

构造函数方式可以为同一个类的每一个对象分配不同的内存,这很适合写类的时候设置属性;但是设置方法的时候我们就需要让同一个类的不同对象共享同一个内存了,写方法用原型的方式最好。所以写类的时候需要把构造方法和原型两种方式混合着用(很多类库提供的创建类的方法或框架的写类方式本质上都是:构造函数+原型)。

构造函数+原型

var Person = function (name) {

    Person.prototype = name;

    Person.prototype.sayName = function(){

        alert(this.name);

    }

}

 

//实例化

var tyler = new Person("tylerzhu");

var saylor = new Person("saylorzhu");

tyler.sayName();

saylor.sayName();

//检查实例

alert(tyler instanceof Person);

这样即可通过构造函数构造不同name的人,对象实例也都共享sayName方法,不会造成内存浪费。

JavaScript压缩/合并

JavaScript代码压缩混淆的意义:简单的说就是为了减小js文件大小,去掉多余的注释和换行缩进等,使得下载起来更快,提高用户体验

JavaScript压缩工具有很多,我推荐使用jQuery现在使用的工具UglifyJSjQuery以前也使用过多种压缩工具,如Packer),因为它压缩性能很好。

jQuery 1.5 发布的时候 john resig 大神说所用的代码优化程序从Google Closure切换到UglifyJS,新工具的压缩效果非常令人满意”

下面是官方性能对比:We’re still a lot better than YUI in terms of compression, though slightly slower. We’re still a lot faster than Closure, and compression after gzip is comparable.

File

UglifyJS

UglifyJS

+gzip

Closure

Closure

+gzip

YUI

YUI

+gzip

jquery-1.6.2.js

91001

(0:01.59)

31896

90678

(0:07.40)

31979

101527

(0:01.82)

34646

paper.js

142023

(0:01.65)

43334

134301

(0:07.42)

42495

173383

(0:01.58)

48785

prototype.js

88544

(0:01.09)

26680

86955

(0:06.97)

26326

92130

(0:00.79)

28624

thelib-full.js

251939

(0:02.55)

72535

249911

(0:09.05)

72696

258869

(0:01.94)

76584

 

Uglifyjs安装

UglifyJS是基于 NodeJS Javascript语法解析/压缩/格式化工具,所以我们要安装NodeJS

N ode.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.

JavaScript最早是运行在浏览器中,然而浏览器只是提供了一个上下文,它定义了使用JavaScript可以做什么,但并没有“说”太多关于JavaScript语言本身可以做什么。事实上,JavaScript是一门“完整”的语言: 它可以使用在不同的上下文中,其能力与其他同类语言相比有过之而无不及。Node.js事实上就是另外一种上下文,它允许在后端(脱离浏览器环境)运行JavaScript代码。

要实现在后台运行JavaScript代码,代码需要先被解释然后正确的执行。Node.js的原理正是如此,它使用了GoogleV8虚拟机(GoogleChrome浏览器使用的JavaScript执行环境),来解释和执行JavaScript代码。

除此之外,伴随着Node.js的还有许多有用的模块,它们可以简化很多重复的劳作,比如向终端输出字符串。因此,Node.js事实上既是一个运行时环境,同时又是一个库。

l  Windows下面直接下载exe文件执行即可。(http://nodejs.org/

C:\Users\tyler>node -v

v0.8.2

l  设置代理(公司网络不设置代理无法下载,外网环境不需要)

npm,全称是"node packagemanager",它是node包管理器,第三方的package全是通过npm去安装的。”

n  npm设在代理

npm config set proxy=http://proxy.tencent.com:8080

n  npm默认选择http方式,不选用https

npm config set registry http://registry.npmjs.org

l  npm安装uglify-js

npm –g install uglify-js

l  验证安装是否成功

C:\Users\tyler>npm -v

1.1.36

UglifyJS使用

uglifyjs [ 选项... ] [ 文件 ]

文件参数应该放在选项后面,uglifyjs 会读取文件中的javascript代码进行处理。如果你不指定输出的文件名,那么他会把处理后的内容输出到命令行中。

支持的选项 

l  -b  --beautify - 输出格式化代码,当传入该参数,下面的附加选项用于更美观的控制格式化:

n  -i N  --indent N - 缩进级别(空格数量)

n  -q  --quote-keys - 是否用引号引起字符串对象的键(默认只会引起不能被正确标志的键名)

l  --ascii -默认 UglifyJS 不处理字符编码而直接输出 Unicode 字符,通过传入该参数将非ASCII编码的字符转化为\cXXXX的序列(输出总按照UTF8编码,但传入该选项能得到ASCII编码的输出)。

l  -nm  --no-mangle - 不改变变量名称

l  -ns  --no-squeeze - 不调用 ast_squeeze() 函数(该函数会做多种优化使得结果更小,可读性略有降低)

l  -mt  --mangle-toplevel - 在顶级作用域打乱变量名称(默认不开启)

l  --no-seqs - 当调用 ast_squeeze() 将会合并多个语句块为一个语句块,如 "a=10; b=20; foo()" 将被转换为 "a=10,b=20,foo()"

l  --no-dead-code - 默认 UglifyJS 将会删除不被用到的代码,传入该参数禁用此功能。

l  -nc  --no-copyright - 默认 uglifyjs 会在输出后的代码中添加版权信息等注释代码,传入该参数禁用此功能。

l  -o 文件名  --output 文件名 - 指定输出文件名,如果不指定,则打印到标准输出(STDOUT

l  --overwrite - 如果传入的JS代码来自文件而不是标准输入,传入该参数,输出会覆盖该文件。

l  --ast - 传入该参数会得到抽象的语法树而不是Javascript,对调试或了解内部代码很有用。

l  -v  --verbose - 在标准错误输出一些信息(目前的版本仅输出操作用时)

l  --extra - 开启附加优化,这些优化并未得到全面的测试。

l  --unsafe - 开启其他附加优化,这些优化已知在特定情况下并不安全,目前仅支持:

l  foo.toString() ==> foo+””

l  --max-line-len (默认32K字节) - 32K字节出增加换行符,传入0禁用此功能。

l  --reserved-names - 一些类库会依赖一些变量,该参数指定的名称不会被混淆掉,多个用逗号隔开

下面是我们使用uglifyjs压缩,PetConfigParser.js的例子:

uglifyjs -nc -mt PetConfigParser.js > PetConfigParser.min.js

PetConfigParser.js压缩前后对比

压缩前

clip_image002

压缩后

clip_image003

JavaScript文件合并

规则1——减少HTTP请求(Minimize HTTP Requests

Yahoo前端优化性能规则[5]

只有10%20%的最终用户响应时间花在接收请求的HTML文档上,剩下的80%90%时间都花在HTML文档所引用的所有组件(图片、脚本、样式表、Flash等)进行的HTTP请求上。因此,改善响应时间最简单的办法就是减少组件数量并由此减少HTTP请求数。

对公共库合并压缩在减少size的同时,减少http请求优化网络耗时提升性能。

YUIDoc 是一个基于 Node.js 的应用程序,用来根据 JavaScript 的注释中生成 API 文档,类似 JavaDocASDoc,这也是当前 YUI 用来生成文档的工具。

YUIDoc安装与使用

l  YUIDoc安装

UglifyJS一样,YUIDoc也是基于Nodejs的一个应用程序,使用npm安装即可。

npm -g install yuidocjs.

校验安装是否成功

C:\Users\tyler>yuidoc -v

0.3.15

l  生成文档(一次性生成)

yuidoc .

一次性生成该目录及其子目录下所有JS的文档 默认在不配置的情况下会生成在当前目录的out目录中。

-o, --out <directory path> Path to put the generated files (defaults to ./out)

l  生成文档(实时生成)

YUIDoc还提供了一种实时文档生成的方式,有利于团队协作开发 比如在SVN上部署YUIDoc实时文档,递交到SVN的代码都会及时生成文档提供团队使用查阅

yuidoc --server

默认开放监听当前目录文件变动,开放3000端口 可以通过

http://127.0.0.1:3000/

来访问文档 如果3000端口被占用,也可以指定特定端口号

yuidoc --server 5000

来通过开放5000端口提供文档访问

YUIDoc标签

要使用YUIDoc,那么所有注释都得安装YUIDoc的标准来,否则不能正确解析出文档。YUIDoc使用的标签和其它语言类同,比较容易理解。下面不详细说明每个标签,只列举几个例子,具体可参加官方文档。例如:

PetConfigParser类进行注释:

/**

 宝宝配置文件解析,及提供查询宝宝配置相关的操作方法<br/>

 * 1. getPetById 根据宝宝id获取对应宝宝的信息<br/>

 * 2. getPetName 根据宝宝的id,读取宝宝信息,然后拼接出宝宝的名字,如3+10天蝎宝宝<br/>

 等等<br/>

 * @author tylerzhu

 * @class PetConfigParser

 * @static

 */

对类中的变量进行注释:

    /**

     宝宝所有配置字典,以【cate * 10000 + (lvl - 1) * 10 + dex - 1】为key

     * @attribute    petDic

     * @type {Object}

     * @private

     */

对类中函数进行注释:

/**

     根据宝宝id,读取__pet_config中对应宝宝的信息

     * @method getPetById

     * @param   {String/int} petId 宝宝id

     * @return  {Object} pet 宝宝的所有静态信息,如{id:"300003289", lvl:"1", dex:"2", price:"200", life:"2592000", cate:"3", name:"飞天小使等级1熟练2", intro:"", skill:"护身符", skill1_prob:"30", skill2_prob:"0"}

     */

默认生成的文档样式如下:

clip_image005

参考链接、进一步阅读

[1]      NodeJShttp://nodejs.org/

[2]      UglifyJShttps://github.com/mishoo/UglifyJS/

[3]      UglifyJS解析/压缩/格式化你的Javascripthttp://goo.gl/bwf8U

[4]      Yahoo前端优化性能规则,http://goo.gl/nfEBg

[5]      YUIDoc文档化JavaScript代码,http://goo.gl/5RJxn

[6]      YUIDoc官方,http://yui.github.com/yuidoc/


4
9
分享到:
评论
3 楼 babydeed 2012-08-15  
写的不错 赞一个
2 楼 long502147 2012-08-15  
构造函数+原型
var Person = function (name) {

    Person.prototype = name;

    Person.prototype.sayName = function(){

        alert(this.name);

    }

}

 

//实例化

var tyler = new Person("tylerzhu");

var saylor = new Person("saylorzhu");

tyler.sayName();

saylor.sayName();

//检查实例

alert(tyler instanceof Person);


这里的 Person.prototype = name; 是不是应该 改为this.name = name; ?
1 楼 lxy2330 2012-08-15  
写的很好啊!收藏起来

相关推荐

    javascript项目优化总结.pdf

    ...

    javascript项目优化总结.docx

    ...

    JavaScript项目优化总结

    JavaScript优化总结分为以下几点优化前后对比代码混乱,同样功能的函数重复出现在多个地方。如果需要修改实现,需要找到所有的地方。牵一发而动全身模块化,提取公共接口组织为库、结构清晰、方便代码重用、并且能够...

    优化RequireJS项目的相关技巧总结

    主要介绍了优化RequireJS项目的相关技巧总结,RequireJS是一个人气JavaScript库,需要的朋友可以参考下

    项目总结报告V2.01

    ①针对可能出现的高并发状况,采用nginx负载均衡减轻服务器的压力,达到优化资源、降低过载的效果 ② ③针对商品审核慢且数量大的问题,采用了rabbitmq消息

    SQL查询安全性及性能优化

    开发是对性能考虑不多【技术差、项目工期紧等原因没有考虑性能问题】 系统运行中,数据量扩大,访问量增多,蹩脚的SQL危害开始显露 低效SQL的危害 系统响应变慢,软件开发中的8秒定律,当打开一个软件或网页超过...

    王红元老师的超级商城项目,vue练完这个就可以直接起飞的,干货满满,代码有详细注释supermall2.rar

    本项目是本人大学期间的一个接近实战的电商商城项目,采用的前后端分离,以及网络请求的封装,注释非常多,适合刚接触前端的新手练手,里面用到懒加载还有一些可复用组件的优化,还是比较值的学习的,大佬勿喷!...

    bootstrap实现登录页面

    Bootstrap一经推出后颇受欢迎,一直是GitHub上的热门开源项目,包括NASA的MSNBC(微软全国广播公司)的Breaking News都使用了该项目。 国内一些移动开发者较为熟悉的框架,如WeX5前端开源框架等,也是基于Bootstrap...

    java从入门到精通70个PPT

    14-15项目案例:当当网上书店或者做一个计算器 16 Ajax 原理 17 Ajax框架 18 在线培训:JQuery 19 Jsp与动态网站初体验 20 状态管理 21 JSTL和EL 22 JSP综合运用 23-24 项目案例:论坛短消息 25-26 项目案例:电子...

    pinyougou:HTML+CSS+JavaScript进行的品优购项目实战

    品优购项目总结本次项目一共实现了7个界面,包括首页、登录页面、注册页面、商品秒杀页、商品推文页、商品抢购页、商品详情页等界面。项目展示首页登录页注册页商品秒杀页商品推文页商品抢购页商品详情页项目技术...

    HTML5触摸界面设计与开发

    第8章 JavaScript性能最优化 113 8.1 性能测试和调试 115 8.2 只写入DOM 116 8.3 给用户反馈的优先级是最高的 117 8.4 将它们一起使用:无限滚动 118 8.5 总结 127 8.6 项目 127 第9章 手势的基本...

    最新Python3.5零基础+高级+完整项目(28周全)培训视频学习资料

    上述内容总结 css选择器 css的存在形式及优先级 css边框以及其他常用样式 css之float样式 css之float实现作业实例 css之display样式 css之内外边距 本周作业以及思路 第15周 上节内容答疑 上节内容回顾 CSS内容...

    前端知识:前端知识脑图总结

    rollup等项目内置工具,以及自动化部署的方案前端性能如何对前端工程的优化方法浏览器浏览器的一些知识前端安全前端xss以及csrfhttp方面http协议相关的内容业务能力面试对工程业务能力的总结和技术总结

    java-sea:打造一个基于springboot的java全知识栈项目。 都是总结好的代码,可以拿去即用

    JAVA SEA概述希望打造一个基于springboot的java全知识栈项目,都是总结好的代码,拿去即用,提高开发效率。因为整个java的知识体系很庞大,为了方便整理,所以一些设计到的知识点都整合到了该项目下,项目模块较多,...

    编程狂人第九期(2014-1-20)

    常用CSS优化总结——网络性能与语法性能建议 编程语言 2013流行Python项目汇总 15款Django开发常用软件包 Rails 3 升级 Rails 4 中遇到的问题及解决方法 php性能优化 Java中的 equals() 和 hashCode() 契约 程序...

    ASP.NET Night Words

    基 础 知 识. 第1章 asp.net介绍 2 1.1 xhtml语言 2 1.2 静态网页 3 1.3 动态网页 3 1.4 iis的安装和配置 3 1.5 asp.net开发的预备知识 4 ...22.6 网站项目和单元测试项目说明 447 22.7 总结... 448

    计算机专业毕业设计-微信小程序案例-微信小程序的学习资料销售平台--论文-毕设源码+说明文档.rar

    项目基于微信小程序原生开发,采用JavaScript、WXML、WXSS等技术进行编程。后端采用腾讯云开发,实现数据的存储和服务器端逻辑处理。数据库采用云数据库MongoDB,确保数据的安全性和扩展性。 **四、二次开发定制** ...

    python入门到高级全栈工程师培训 第3期 附课件代码

    06 函数式编程尾递归调用优化 07 map函数 08 map函数filter函数 09 reduce函数 10 map reduce filter总结 11 内置函数part1 第17章 01 课前吹牛 02 zip方法 03 max和min高级使用 04 其他内置函数 05 文件操作的...

Global site tag (gtag.js) - Google Analytics