Those who forget good and evil and seek only to know the facts are more likely to achieve good than those who view the world through the distorting medium of their own desires. (那些忘记善恶,只顾追求事实的人,与那些因欲望扭曲事实,只看到自己想看的东西的人相比,更容易达成善举。)

- Bertrand Russell

《通用JS时代的模块机制和编译工具》的幻灯片和……剧本……

December 19, 2010

昨天在D2前端技术论坛上的演讲居然很顺利,因为是第一次演讲,我本来是完全没信心的,一个月前头脑发热答应了这件事,但是拖到最后三天才开始准备,演讲前一天只睡了4个小时,因为睡觉前刚赶出幻灯片的最后一个章节,比这些更可怕的是,本来我想逃避“口头表达”,希望演讲就是用slide说话、演示几个DEMO、把控制台和编辑器投影到大屏幕上秀给人们看……所以我在倒数第二天的时候通宵做幻灯片,图文并茂五颜六色各种效果全用上(现学mac上的keynote),没睡觉,白天在公司里试讲,只面对五六个人,却一个字都说不出来,不知道怎么即兴讲解幻灯片(特别是代码片段),连直接读幻灯片上的文字都做不到……当时便有一种必死无疑引颈就戮人生终点就在后天的感觉。

因此我做出一个艰难的决定——把演讲变成念台词,不但要准备slide,还要准备完整的讲稿,每一页slide时要说什么,有没有很难发音的词汇,什么时候停顿,点几下鼠标,都先做好万全的计划。最后一天全在忙这个,还测试了如何把ipad藏在讲台上念稿,好像找回了当年高数考试前天晚上策划作弊的亢奋感觉。

结果昨天上台时一切顺利,80页的slide刚好在50分钟左右讲完,最后一个章节没有来得及准备讲稿,却即兴的讲了很多,最后QA环节回答问题时甚至说得不想停下……现在想想,那天试讲主要的问题其实是没睡觉,缺水,颅内温度很高,大脑某些部分罢工了……

当然也有遗憾,不是会场比较小(人多了不知道会不会紧张),而是我在slide里准备的笑点……比如绝望先生的配图……没有产生任何效果。感觉演讲这种事情如果要产生最大的效果,还是更依赖情感交流,而不是内容交流……

另外我回家之后发现标题是败笔,很多人可能会把“CommonJS时代的模块和工具”理解成“CommonJS的模块和工具”,以为我要讲CommonJS……这可是前端论坛啊,其实直接叫“通用JS时代的模块和工具”就行了……

以下是今天分享的主题的slide和……龌龊的剧本(原封不动的草稿)……这样真好,连视频都不用等了,不过剧本缺最后关于工具的那个章节。另外虽然我写了这么多关于演讲的感想,但我还是希望这篇blog的反馈是关于JS模块和编译工具的……

PS: OzJS这个名字来自绿野仙踪的奥兹国,迪斯尼正在拍“The Great And Powerful Oz”……

1
大家好,今天我要分享的主题是,CommonJS时代的模块机制和编译工具
其实最早我发给小马的主题,是叫做“后浏览器时代的JavaScript——通用模块和辅助构建”
不过后来担心那个标题有点晦涩可能引起误解,
以为是讲软件工程啊流程啊方面的东西……所以就改成现在这样
不过还是有点长有点复杂,不知道大家看到这个标题会怎么想的

2
嗯可能有些人是这么想的……(点)(回头看PPT)

3
嗯不过接下来就会产生疑问……
(点)(回头看观众,停顿)
我想问现场一个问题,有多少了解,或者听说过CommonJS?

4
除了这个问题(点)
可能还会有人对时代这个词感觉比较奇怪

5
最后可能有人要问,(点)为什么要讨论模块和工具,
因为这个不像前端性能啊什么的,是大家都关心的热点
所以我觉得今天这个主题有必要先来作一下回顾

6
先来看看前端日常工作中存在的问题
(点)……这是一张以前在土豆办公室拍的照片,
中间是我,友下角有上上次D2做分享的李戎同学
这张照片看上去蛮河蟹的,其实这些人不是在做前端日常工作,而是在上班时间打游戏

7
先来回顾一下现状
(点)嗯,因为我比较紧张,可能口头表达的不太清楚,请大家直接看幻灯片上的文字
比如拿土豆网来举例,土豆从06年开始,做了一些比较之后开始使用jQuery
而到了07年,我们开始逐步积累自己的代码库
我们并没有逐步替换jQuery,但是也没有采用jQuery的结构和扩展方式去构建代码库
实际上就是把jQuery当作JS的一种内部DSL来用,DSL就是领域语言的意思
到现在也封装出了很多东西,比如常用的编程模式,web应用的模式,工具库,UI组件,等等
平时也注意把需求尽可能的抽象,让代码尽可能的可以复用,也就是不开发重复的东西
(点)这个好像是去年做的一张代码库的结构图,
现在已经过时了,不过可以看到代码单元还是蛮多的

8

9
接下来我们看一下这种现状带来的问题
(点)因为虽然有很多流行的库和框架,但是并没有真正的主流
于是不同的公司、不同的团队、不同的项目,
就可能会有各自不同的代码组织结构,不同的接口风格
这样积累下的代码就有很强的依赖性,
只能在特定项目、特定的公司里使用,或者只能在特定的团队里得到复用
就是说虽然我们重视代码复用,但是事与愿违,代码经常难以在不同项目不同团队之间迁移
难以在不同项目不同团队之间得到管理维护
如果有了独创性的东西,也很难分享到外部,很难得到广泛传播
最后的结果就是大家都在闭门造车轮。

10
来看看第二个现状(点)
比如土豆的前端代码在上线前要经过好几个环境
有开发环境,测试环境,还有跟线上数据完全一致的测试环境
最后这个测试环境中使用的静态文件(比如JS,CSS)都跟线上一样是来自CDN的,
修改后在CDN中同步要等10几分钟,在页面里生效又要等几分钟
每次做了修改,就算是简单的bugfix,也要经历很多环节才能发布上线
(点)这是土豆网首页HTML底部的截图
可以看到上面的红圈是系统自动生成的静态文件版本号,用来控制浏览器缓存
下面这行注释后面的代码是从UI文件服务器上自动抓取嵌入到页面里的
这个首页本身也是静态化的

11
这些流程也带来一些问题(点)
我一直很反对的是,在改进过程的时候损害开发者的利益
如果过程改进增加了开发成本,不应该觉得是理所当然的
而是说明有某些地方没做好,或者缺少了某些东西,比如工具
好的过程应该能隐藏复杂性,减少出错机会。
同时这些环节也对代码的管理提出更高要求,
比如有些代码需要独立的测试,每次修改也要缩小影响范围,
很多东西都依赖代码单元和文件的粒度。

12
第三个现状
这个应该不用解释,上周我刚参加过北京的velocity性能大会
可以看到现在大家对前端性能都是很重视的。

13
这里存在的问题是跟上一条相关的,
比如最简单的例子,为了方便代码的调试维护,我们会希望把JS文件拆分的很细
比如一个UI插件,希望它是独立的文件。
但是性能优化又要求减少页面里的文件请求数
为了尽可能利用浏览器缓存,可能还需要多个页面共享同一个大文件
这两方面的希望是互相矛盾的

14
刚才回顾了三个方面
他们都对同一个问题提出了要求
(点)就是JS代码本身的组织管理和使用

15
解决的途径之一,就是标题里提到的两个东西

16
这个标题可以拆成三部分
后两个是手段,第一个是背景,先来看一下这个背景

17
在这里我把CommonJS翻译成通用JS,接下来就可以看到为什么要叫通用

18
CommonJS是目前广泛流行的一套API规格
不叫它标准是因为它并不是来自像W3C,ECMA这样的官方组织
而是业界自发组织起来,发展出的项目,而且也正在在逐步成为一个事实标准
事实标准这个词是来自拉丁文的修辞,
意思是法律没有规定,但是“在事实上”或者“执行上”是怎样做
(点)它的反义词则是指有明确的法律,但是人门在现实中不会遵守
说到这两个词我们可以很容易的联想到HTML5和XHTML2,一个典型例子
这个民间项目关注的是更广义的JS开发,不止是浏览器
它的目标是建设一个JS的生态系统

19
有人可能会说现在的JS难道没有生态系统么
但是既然业界有这个目标,就说明即使有生态系统,也存在一些问题
当然其中一个问题是JS缺少服务器端开发需要的API,不过这个不是今天的重点
(点)python,ruby跟JS一样是动态语言,也非常流行,他们有内置的标准库
特别是python,有一个著名的宣传口号是“内置电池”,因为标准库非常全面
除了标准库,他们还有一个更庞大的由社区建立的代码库,其中CPAN是最早最有名的
很多人就是因为这个CPAN的存在,才会选择这个语言或者无法摆脱这个语言
JS我们知道也有大量的开源代码,但对你来说并不是每个代码都能用
比如有的是JQUERY插件,有的是YUI插件
还有一些独立的库即使很小,也必须包含重复的功能,因为它不能依赖其他东西
另外那些在浏览器里运行的代码拿到服务器端当然就更没法用了

20
比如这个例子,是我用Python写的翻墙工具,代码的第一行就是在导入标准库
包括操作系统相关,文件读写,正则表达式
下面几行我又使用了几个第三方代码库,其中的mako是一个HTML模板引擎
要获取这个库,我只需要使用Python的包管理工具
一个命令就能查找、下载、安装它自身和它依赖的其他库,而且都是最新版本
这些东西对开发带来了很大的便利,大幅提高开发效率。

21
回到CommonJS, 最早是在09年初,这个叫kevin的人建立了讨论组,最早其实是叫ServerJS讨论组
他当时写了一篇文章叫《服务器端JS需要什么》,所以最初的推动力是来自服务器端开发的需求
因为如果只局限在浏览器的特殊文化里,不接触其他语言,很多问题和需求可能都察觉不到
这个人是Mozilla的开发者工具团队的工程师,这个团队的创建和它发起的项目都很有名的
比如skywriter可能有人听说过,是一个用JS开发的在线版本编辑器
他好像是turbogears项目的创始人,turbogears是一个python的web开发框架
国外著名的开源项目网站sourceforge的新版就是用它开发的

22
Commonjs本身不提供任何具体实现,它只是约定一套东西,由兼容它的项目去实现,
按照这种约定开发出来的JS应用和模块,不做修改就可以在这些兼容COMMONJS的平台上运行
而我们最需要关注的是它对于模块的约定,后面会介绍具体的代码怎么写

23
接下来看一下广义的通用JS
其实我是借用这个词来概括当前的趋势和背景
它包含两层意思,一方面是在更多领域更多环境里需要使用JS,就是说JS本身通用了
另一方面,JS代码也需要变得通用。

24
我们来看几个例子

25
首先最自然的延伸,浏览器扩展
firefox是最早用JS开发扩展的浏览器,因为实际上它浏览器本身的界面也大量使用JS
但是以前的firefox扩展开发门槛还是很高的,比如要学习XUL,要使用C++的API
现在新的jetpack SDK不但提供了高层的JS API和测试工具,打包工具
还提供了兼容CommonJS的模块机制,让扩展开发轻松了很多

26
比如这是我以前用jetpack SDK的早期版本开发的工具软件,可以算一种自动化测试工具
简单概括就是一个爬虫,提供一个网址入口,它可以顺着超链接一路爬下去
找出所有相连的网页,并且对每一个网页应用你自定义的脚本,最后输出脚本结果的报表
因为这个不是主题而且有时间关系就不演示了
来看看它的代码,其中有一部分界面相关的JS还是以前firefox扩展的写法
不用解释就能看出代码很丑陋吧
这个是新的写法,比刚才清晰多了,可以看到我导入了几个API,每个API都是一个模块
request模块就是AJAX,pageworker相当于iframe,还导入了我自己的库TUI

27
除了firefox,其他浏览器也都开始支持用JS开发扩展,目前最火的当然是google的chrome
我这里给出一个safari扩展的例子,因为还没时间移植到chrome上
这个扩展完全用JS,HTML5和CSS3开发,只用到一张图片,UI和动画效果都是CSS3实现的
开发的时候非常方便,不过也有不爽的地方
就是它的JS没有模块化设计,apple提供的API很少,还做了很多麻烦的限制
其实我一直觉得chrome的扩展开发虽然比firefox简单,但是很难开发很强大很给力的应用

28
再来跳出浏览器,看看移动平台上的例子
(点)比如nokia目前基于厚望的QT Quick,QT本来是一个C++的GUI库
因为这一点有很多不喜欢C++的人不愿意用它,为了讨好开发者
QT quick包含QML,可以用JS和类似JS的声明式语言来快速开发手机或平板电脑上的应用

29
当然更有名的是webOS,应该多数人都听说过了
这个移动操作系统一开始就要求所有软件都用JS开发
新的2.0系统更进一步集成了nodejs,后面会做介绍,它也是CommonJS的兼容实现
也就是说我刚才给firefox扩展开发的JS模块可以直接拿到这里使用

30
除了新的移动平台,电脑桌面上其实也有很多GUI库使用了JS
这里举一个比较新的国产的例子,是豆瓣的洪强宁开发的
这里的ONERING是指魔戒里的一枚戒指统御众戒
所以这个名字意思应该是说同一种JS技术可以开发多种界面
不但能开发web上的,也可以开发桌面上的
我给他提过一个建议, 最好能兼容COMMONJS

31
下一个例子是今年欧洲JS大会上一个演示,这个演示的幻灯片里包含几个饼图
黄色是客户端,蓝色是服务器,紫色是嵌入式
可以看到09年第一届JS大会上的分享100%是关于客户端开发的
到了下一届有1/5是关于JS在服务器的应用,再一下届变成一半比例
到了这一届甚至出现了嵌入式开发,作者希望到下一届能各占1/3

32
实际上这10%的嵌入式内容是指作者自己的分享
他们希望能用JS控制一种在国外非常流行的开源硬件平台

33
这个视频演示了他们使用nodejs开发server,
然后在ipad上通过web界面里的JS代码遥控硬件设备
因为时间关系不在这里播放了……

34
最后的例子当然是服务器端的JS了
目前的绝对主流就是nodejs
传统的服务器端JS都会让人觉得很不靠谱,跟ASP之类的东西差不多。
nodejs的靠谱之处在于它的出发点不是为了在服务器和浏览器用同一种语言做开发
这种需求只是一种个人喜好,不一定是最好的选择,也不一定有实用价值。
nodejs想要推广的是基于事件的异步编程
这种编程模式对我们前端开发者来说好像是天经地义的
因为我们已经习惯了浏览器里的各种DOM事件和匿名的回调函数,
AJAX请求,图片加载,也都是异步的
但是对服务器上的开发者来说这是一种需要额外支持,需要努力去适应的模式
JS天生就提供这种支持,而这种编程模式的好处
就是可以适应大规模并发和实时性非常高的服务器应用
比如像webQQ这样的东西。
第三条里提到的erlang (erlan) 是以并发性能著称的函数式编程语言
Nodejs被拿来跟它比较,就算比不过,也说明Nodejs性能有竞争力

35
具体的例子因为时间关系就算了,重点是想强调一下它的模块数量
/*
这里如果是乔布斯演讲,幻灯片上应该会掉下一个很大的550
*/
github的一个wiki页面上收录了很多Nodejs的第三方模块
我随便抓取了一下数量,有550个以上,涉及各种功能。
对于一个发布刚好一年的项目来说这应该算蛮惊人的。

36
回头来看浏览器上的JS,跟刚才的一对比就会感觉通用的模块太少
这里说的通用还仅仅只是在前端,在不同项目不同团队不同公司之间通用
前端的JS社区很分散,jquery有jquery的社区,YUI有YUI的
虽然有一些互相借鉴但是还是有很多东西只在内部传播和使用
外部的开发者是不了解的,也不会去用
而且缺少有利于分享的基础设施,这里说的基础设施不是指开源网站
当然那个也算,这里要说的是更底层的设施

37
其中之一就是模块机制,也就是这次分享的第三个部分

38
先放大视野,看一下其他语言里的模块是什么样子
(点)先请出刚才提到过的python, python代码很简洁,相信没用过的人也看的懂
(点)这里一个框表示一个代码文件
这个文件导入了模块B,然后调用模块B里的say方法
模块B的用法就像这个文件里的一个普通对象一样
(点)模块B定义了两个变量和刚才调用过的say函数
而这个函数里又调用了一个叫cat的类,生成猫的实例,让它叫一下
但是模块B文件里并没有cat类的定义,看第一行可以知道这个类是从模块A里导入进来的
(点)模块A文件里也定义了a变量,但是因为没有声明导入它,
所以不会覆盖模块B文件里定义的a
这个就是python里模块的基本用法
从中我们可以总结几条python模块的特性

39
可以发现这些特性都符合开发者的直觉,也符合开发的需要,
对模块的开发和使用都很有好处
这里没时间演示其他语言的模块,比如ruby, actionscript3,但是这些特性都差不多的
看了这个列表, 我们还可以发现另一件事情
(点)浏览器里的JS不符合其中任何一条

40
可以对比一下:
JS存在全局作用域,不同文件会共享同一个全局命名空间(点)
所有文件一开始都会解析执行(点)
没有相关的声明语句,只能用异步加载文件的方式模拟导入的效果(点)
导入之后不管你想不想要,那个文件里的东西会全部注入到当前的命名空间里(点)
可能隐式的导入很多全局变量,覆盖或修改当前的内容(点)

为了避免这种情况,模块文件就不能采用最自然最简单的写法,比如直接定义变量和函数
而必须把所有东西都放到一个特殊的命名空间下面,比如jquery.js就是这样

JS文件自身也不包含依赖信息,如果有打包合并之类的操作
我们可能会把依赖信息写在另外的配置文件里(点)

41
我们来看看JS的代码通常是怎样组织的
(点)这个是最传统的写法,现在仍然有人在用
(点)某个网站的HTML截图,文件的顺序就是代码的依赖关系
(点)这个已经算是比较新的方法,用工具自动合并这些文件
但是如果这张图里的文件还是刚才那些文件,本质上是没有区别的,仍然依赖从上到下的顺序

42
因为这些传统,我们对浏览器端的特殊文化已经习以为常,见怪不怪了
可能没有觉得有什么不对,但是时间长了会觉得很麻烦和低效
不过最后这一条起到了一定的正面推动作用
为了改善前端性能,很多开发者开始尝试封装出一些工具

43
我把它们称作脚本加载器

44
比如这个例子,它的API提供了串行和并行加载脚本文件的功能
最大的特点应该算是用类似jquery的链式调用风格来实现串行加载
(点)(点)

45
这是另一个库,API风格有很大不同,我们看看有没有新功能
(点)(点)所以这里的并行下载,按依赖关系执行,
只是用预加载技术模拟出来的效果,实际上会请求多次
而且依赖关系仍然取决于前后顺序(点)(点)(点)
本质上还上一个库是一样的

46
最后一个例子是土豆自己的(点)(点)
JS文件名里包含在版本号是在HTML里自动生成的
(点)(点)
(点)虽然当时命名成module,本质上还是脚本加载器

47
除了大同小异的脚本加载器,我们还习惯了另一种代码组织方式
(点)这种模块模式同样也是为了克服之前列举的JS的缺陷

刚才列举的这些东西虽然有帮助,但是跟其他语言原生的模块支持相比,仍然差距很大

48
于是有人提出了更本质上的问题:JavaScript需要模块!
(点)这个名字叫戴夫赫尔曼的人并不是随便说说而已
(点)他的条件很好,跟JS创始人在一起工作,而且是TC39的成员,
TC39是负责制定下一代JS标准的小组
所以他直接发起了一个新提案,希望给JS语言加入simple module的功能

49
第二个链接是他在TC39会议上做的演讲,描述了simple module的目标和初步设计
下面这个N开头的东西是mozilla开发的实验性JS引擎,可以快速加入新功能做测试

50
简单来说他设想的simple module就是这个样子
增加了四个重要的声明语法,虽然语法很简单,但是有了这四个词之后,
JS就完全具备了跟python模块一样强大的功能

51
刚才的代码没看的明白也没关系,因为第一,它目前还只是一个稻草人提案,
就是说这个提案的功能是吸引更多人来讨论它的缺点,从而产生新的和更好的方案
第二,它是一种新引入的语法,跟CommonJS不一样,CommonJS是要用现有的语法去改善JS开发
而simple module的初衷是直接改善JS语言本身,
ES5的邮件列表里有一个相关的讨论,JS创始人布兰登也发表了意见

52
虽然短时间内不能用,但是可以先借鉴一下这个提案里列举的目标
我们是否能利用现有的JS语法和功能,来追求这些目标,实现比较理想的模块机制呢

53
之前好几次提到CommonJS的模块,现在终于轮到讨论它了

54
先请出之前展示过的爬虫程序,在介绍firefox扩展的时候,提到过它实现了CommonJS的模块
这里给出的两段代码分别来自同一个模块文件的顶部和底部(点)
圈出的部分就是CommonJS模块的主要特征(点)

55
(点)把之前python模块的示例代码,直接改成commonjs的写法(点)(点)功能特性完全一致
区别只是导入模块时不是用声明语句,而是调用require函数
可以说CommonJS满足了之前提出的所有要求,
在不引入新语法的前提下,实现了比较理想的模块机制
可惜这种代码完全没办法在浏览器里使用,障碍有两个:
第一,网页里不同JS文件之间全局命名空间是共享,而服务器端CommonJS里每个文件都是独立的
第二,require函数是阻塞式的,读取完模块文件,并返回模块对象之前,不会执行后续的代码
在服务器上这是很自然的,但是在浏览器里,读取文件是异步操作,阻塞会影响页面的交互
所以没办法、也不能让require函数阻塞代码的执行

56
于是现在要解决的问题转变成了这个了
不过在讲解决方案之前,我要先插播两页

57

58

59
嗯接下来开始介绍浏览器里的CommonJS兼容实现:RequireJS
它的开发者比我条件好,近水楼台先得月……
它定义了两个方法,require和define,其中define是关键设计,
已经成为了新的CommonJS规范,叫做异步模块

60
来看看所谓异步模块是什么样的
(点)还是跟之前Python模块和CommonJS模块的示例代码保持一致(点)(点)
可以看到require变成异步调用,第二个参数是匿名函数,
这个函数的作用域相当于模块文件的顶层作用域
作用域里的代码可以跟服务器端CommonJS完全一致,
包括使用阻塞式的require,用exports生成模块对象
这个作用域里也可以直接采用传统的模块模式的写法,用return来生成模块对象
依赖的模块会被转变成模块对象,通过函数参数传入
define函数具备require的所有功能,同时提供了定义新模块的能力,
当模块代码位于独立的文件里
比如像这里的模块A,模块名称的参数可以省略,直接绑定到文件名

61
异步模块的require和define还有一种衍生的用法,就是用来请求JSONP接口
define不但支持传入函数,也可以直接传入一个对象作为模块对象
用这个方法请求JSONP的好处是不用担心callback污染全局命名空间,
还可以起到缓存的效果,因为模块文件只会加载一次

62
总结一下异步模块的优点

63
刚才说过requireJS算是异步模块的一个官方实现,
不过相比之下我更喜欢自己实现的oz.js
一个原因是代码更少更简单,另一个原因是我对define函数的用法有不同的意见
requirejs仍然采用服务器端的做法,把模块名直接等同于文件地址,
但是前端开发中很少有这么理想的情况
而对于要下载的JS文件不需要做静态的声明,只在运行时里检查,也会产生很多不便

64
对照代码看看oz.js的def方法有什么不同

65
内部细节只强调几个功能上的问题
oz.js本身包含了前面提到的脚本加载器的所有功能,但是只会用到并行加载,
因为模块文件之间没有依赖关系。

66
在模块部分的最后引用一下这句话:“让代码更容易分享,大家就会分享更多的代码”。

posted in 代码 by Dexter.Yy

Follow comments via the RSS Feed | Leave a comment | Trackback URL

53 Comments to "《通用JS时代的模块机制和编译工具》的幻灯片和……剧本……"

  1. Michael wrote:

    这样真不错, 很少有人能在讲完后还提供讲稿的XD

  2. sheperdwind wrote:

    昨天跟着谷歌大神去了,正遗憾错过了土豆的演讲呢。补一补。呵呵,其实昨天淘宝就在广告旺铺装修市场和kissy了

  3. sheperdwind wrote:

    一口气看完,实在精彩。
    你的演讲包含了三楼两个讲得最精彩的部分:google的Hedger也谈到了js性类问题,通常我们为了兼容性与代码可管理性,开发一些js类库,诸如大名鼎鼎的jQuery,YUI,他们都会在客户端作检测,这个数据是不是我想要的类型,或者是利用一些奇怪的技巧实现js的面向对象——私有变量,继承,等。而他认为这些方法都是把性能的代价放在客户端,让用户的电脑来处理这一切。然后提到了谷歌的解决方式,使用Closure Compiler,这个和TUICompiler有些像哦,都是在服务器端重新编译js,并且压缩。Closure Compiler依据jsdoc来编写面向对象的js代码,使用注解来声明继承,私有变量等。Closure Compiler负责处理其中的错误,最后生成客户端js,只把有用的js给用户。
    第二个是来自盛大的老赵,他开发了Jscex,实现的也是js异步动画。盛大当然专注于游戏,Jscex是在js动画中实现你上面代码所谓的wait()方法,只是这个wait是等待一个状态的完成(这里把js时间封装起来,否则在动画中回被事件的调用折腾死),而不是一段代码的加载。
    当然,你们有很多相同的东西,但是也有不少不一样的思想,都很有价值。
    土豆的前端很强嘛,我在自己博客上一不小心把中国的前端说成是07年始于淘宝,Aether立即反驳:我05年就是以前端工程师加入土豆的……

  4. dexbol wrote:

    土豆前端 确实强悍。

  5. su27 wrote:

    Onering的开发人手太少,有想法欢迎贡献代码哦

  6. George Wing wrote:

    YY很强大,学习了~

  7. 小葱 wrote:

    YY很强大,学习了~

  8. qnhspsqklfjg wrote:

    owomyiurhrdy

  9. rjggedtjgzow wrote:

    evpncentjbfg

  10. ecqwyuerdpov wrote:

    yoqawdvdgnfv

  11. dnnuvciamooz wrote:

    rpkkgnbticab

  12. rbsaefgdhaid wrote:

    gbbsjrvghpih

  13. vmgvoxoxxtna wrote:

    xqedfzdoired

  14. deyfgddtarfm wrote:

    loqnsuxevgmr

  15. rlcfnsunkxzw wrote:

    nxdpmwnpemzv

  16. aoxsfdzxznff wrote:

    sjamaeicetbp

  17. exqvywkkfdvh wrote:

    kkztlxlfmnrr

  18. glevbkgqdrek wrote:

    ocefdhjoeqcw

  19. rdejckpvvsze wrote:

    ibeiibltwyre

  20. ymxhpdizcijn wrote:

    vkvnnbuutcsd

  21. hvydidnngisi wrote:

    xqooqrzvglsq

  22. eezbrgltfoii wrote:

    hzigmwglmojo

  23. brvudfmphpug wrote:

    bysnblinwebc

  24. bnvsbuaytnil wrote:

    zhevysajxdgs

  25. oudqihyccqkp wrote:

    mgvmqvdvpvqq

  26. tpgxqusasezv wrote:

    wixsvjaccpby

  27. khzrigubkvhl wrote:

    qzwidhqoazlw

  28. ctbtilyezixw wrote:

    osowjigumpbg

  29. omptgcexxlhv wrote:

    yksnwokumdoo

  30. ktwxdgpetlng wrote:

    gclvdscehpwb

  31. fzwvfsoeaklz wrote:

    iicnerllphtm

  32. ewmobagjwepd wrote:

    qgsetciyhowz

  33. jecamlsevivc wrote:

    sxlmbzxtnsim

  34. gzcbsvkgencs wrote:

    qxeeyxytbcft

  35. dapsaeophkiz wrote:

    inddtvgzqhgy

  36. ofjqklrtuqiw wrote:

    ajkbtojpstsc

  37. kfgbgdvjzlzf wrote:

    qpuirnxfevru

  38. nlaerpkakdvh wrote:

    euvmuwjydhmt

  39. hvaiwqjlqvse wrote:

    pdwirchknbqr

  40. tyymyurbymuf wrote:

    rnwjiivlurma

  41. zjenheifhuhi wrote:

    dhspbnqtfxwv

  42. gboserlyorng wrote:

    ebdztevjweqm

  43. wfekmboqvkpi wrote:

    cbffyjvujiye

  44. jexxworkzlaq wrote:

    gobszbydlqew

  45. dlqdepycuxcy wrote:

    yriqmvjephoz

  46. cgnapjzmbpsg wrote:

    ziipqbxjvnxz

  47. usvxajaxuriz wrote:

    tybftcbonllo

  48. tbgfrzqcuuxu wrote:

    czoyvgorqfxz

  49. amuinzkkddat wrote:

    uwbzjxyizgvg

  50. hrtzsiysaayn wrote:

    prpaymbfiglf

  51. coldsoreremediestoday.webs.com wrote:

    It is a cop-out statement by folks who really do not understand what it is like to suffer cold sores like us.

    This chemical is flammable and should be kept away from any type of
    open flame. These are two amino acids (proteins) that play an important role in
    the replication process of the herpes simplex virus.

  52. urodziny warszawa wrote:

    Wow, incredible blog layout! How long have you been blogging for?
    you make blogging look easy. The overall look of your site is magnificent,
    as well as the content!

  53. jordan vi retro wrote:

    It’s an remarkable piece of writing in favor of all the online viewers;
    they will get advantage from it I am sure.

Leave Your Comment

YY in Limbo (混沌海狂想) © Dexter.Yy

Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution - NonCommercial - ShareAlike 3.0(署名-非商业性使用-相同方式共享).
Creative Commons License