`
H雨心Y
  • 浏览: 8000 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

YUI3设计中的激进和妥协(转)

    博客分类:
  • YUI
阅读更多

相信每个前端工程师都有自己喜爱的javascript框架,说情感也好,道信仰也罢,javascript框架带给人的不仅仅是便捷的开发,更有一种纯粹的逻辑美感,不管是jquery曼妙的简洁,还是yui魔术般的沙箱,都使我们产生无穷的想象。然而,js框架却又必然无法做到面面俱到的完美无瑕,比如jquery在OO方面做出的让步,以及yui在性能上做的牺牲,无不给人传达一种缺憾美、一种理想的现实主义。今天,我们来看看yui3在框架设计中的这些牺牲和让步,以便让我们更加深刻的理解yui3的全貌,并将其优势发挥至最佳。

1,种子的一步到位 or 颗粒化
所谓种子一步到位是指只要在页面引入一个种子文件的script标签,比如prototype和jquery,只要引入一个prototype.js或jquery.js就可以了,他们将各自对dom操作和event的封装等等都囊括进一个文件中,并尽力将其做到最小,这样做的好处是显而易见的,使用框架非常简单。然而yui将这些功能做了级别划分和颗粒化设计,从概念上抽象出来“核心”、“工具”和“组件”,每个小功能放在一个文件当中,需要的时候则要自行去引用,yui文档中给出的大量demo都采用这种方法,这种设计显然不像jquery那样对初学者友好,而且使用起来不够傻瓜,为了实现一个小功能,甚至要引入三四个js文件。yui这样做的原因有两个,一是yui实在太大,把所有功能都搞进一个文件中确实有点不靠谱,二是为其动态加载的框架设计做铺垫。

2,手动引入 or 动态加载
往页面中写js的传统方法是,直接将js文件作为script标签路径写在页面中,使用yui也可以这样引入页面,但yui更推荐使用loader进行动态加载。动态加载脚本的渊源很复杂,目前来看主要原因有三,其一,页面中手写js标签无论如何都会占用一个http请求,即使这个请求是一个304,动态加载的文件缓存后则不必发起真实的http请求,其二,动态加载可以实现按需加载,而且可以根据js文件之间的依赖进行去重和排序,手写标签加载js文件则必须让开发者去额外关注一下文件的排序、重复等等,其三,动态加载有利于页面代码的语义化,这使得开发者只关心“需要什么”,而不用去在意“如何得到”。当项目变得越发臃肿,维护成本越来越高的时候,这中小技巧会有不小的好处的。

 

3,逻辑启动的单一入口 or 沙箱
我们在页面中启动一个js逻辑通常是放在一个类似onDomReady的方法中,如果页面中存在多个逻辑的时候怎么办呢?比如,a实现了逻辑A,页面代码是这样的

<script src=”logicA.js” />
<script>
$.onDomReady(function(){
___LogicA.start();
});
</script>

这段代码通常写在页面的尾部,这段逻辑所伴随的html代码是埋藏在页面的某处,这时b要在页面中增加逻辑B,b的做法是首先找到尾部的这段代码,然后更改成如下模样:

<script src=”logicA.js” />
<script src=”logicB.js” />
<script>
$.onDomReady(function(){
___LogicA.start();
___LogicB.start();
});
</script>

同样,B逻辑所伴随的html代码也是埋藏在页面的某处,这样看来,js逻辑和其伴随的html代码如此分离,以至于到了删减功能的时候,往往删掉html却忘了删js,或者删掉js忘了删除html,在重用代码的时候也会是个麻烦。同样,在调试的时候,工程师也要打开两个窗口分别关注js和html,即使这两段代码在同一个文件当中。如此则不如把代码写成这样:

<!–A逻辑的html代码段–>
<script src=”logicA.js” />
<script>
$.onDomReady(function(){
___LogicA.start();
});
</script>

<!–B逻辑的html代码段–>
<script src=”logicB.js” />
<script>
$.onDomReady(function(){
___LogicB.start();
});
</script>

这种coding写法正是yui所提倡的,也就是所谓的沙箱,每个逻辑包含在一个沙箱中,各司其则互不干扰。当第三者浏览代码的时候也立即明白这就是一个独立的功能块,包含典型的html结构和启动逻辑的js,要重用,整块拷走即可。

4,代码污染 or 沙箱
刚才提到的沙箱可以解决一部分代码污染的问题,新人阅读代码不用再看着乱码般的源码,“瞻前顾后”小心翼翼的寻找html和js的对应关系。但这种写法也存在隐患,现在的前端开发越来越复杂也更多的使用分层,比如底层使用yui,中间层是自定义的工具库,或者再加一个项目的widget组件库,写页面逻辑则是基于这些库进行开发。这样的话,每段逻辑可能写成这个样子:

<!–A逻辑的html代码段–>
<script src=”widget.js” /><!–项目的widget库–>
<script src=”logicA.js” />
<script>
$.onDomReady(function(){
___LogicA.start();
});
</script>

尽管我们可以约定,将项目用到的所有的组件都统一加载进页面中,但当组件越来越多的时候,就出现了上文所说的一步到位和颗粒化之间的矛盾,当每个控件单独占用一个js文件和与之相伴随的css皮肤,一个相对复杂的逻辑就变成了上文所说的手动引入js文件,并随之引入一些显而易见的弊端:

<!–复杂的A逻辑的html代码段,使用了日历,弹层,幻灯–>
<script src=”calendar.js” /><!–日历–>
<script src=”box.js” /><!–弹层–>
<script src=”tabview.js” /><!–幻灯原型–>
<script src=”slider.js” /><!–幻灯–>
<script src=”logicA.js” />
<script>
$.onDomReady(function(){
___LogicA.start();
});
</script>

首先,手写大量的js文件会各自占用单独的http请求,在者,这个场景中,slider.js继承自tabview.js,因此要着重关注他们的顺序,第三,如果别人在页面的其他地方也使用了日历或者幻灯,还要再加两个相同的js标签?其实,说到这里,我们已经可以隐约看到大项目团队开发的影子了,在一个迭代及其频繁的项目中,开发者需要在短的时间内完成一个复杂页面的某个功能的开发,而且不能影响到页面的其他功能,毕竟,每添加一个功能,QA mm们都要将与之牵连的所有功能都要回归,可辛苦了我们的QA mm们。在这种情况下,一个功能的开发可能和同一个页面其他功能的开发相互并行。互相不属于同一个项目组,也不知晓对方的实现。这种模式则是我们经常遇到的多人开发,冲突也大都由此产生,每个功能单独看来是正确的,合并到一起会产生冲突和bug,这时调试bug则需要两个工程师同时进行,很麻烦。甚者,当组件升级了,比如,tabview.js再继承自tab.js,则又要去联系各个工程师,将每个引用tabview.js的地方之前再加上一个tab.js,很麻烦。我们说,这种多人协作模式所带来的冲突也是代码污染的一种,因为每个人只能掌控类似tms区块那么巴掌大的地方,所组成的最终页面是什么样,都不知道。更何况,这种生猛的引用js,也会阻塞页面加载,占用http请求,影响性能。

鉴于此,yui将js的动态引入机制也并入其沙箱设计之中,我要引用的只是一个名字,比如slider.js,他依赖tabview.js,tabview.js依赖tab.js,这样我只需引用一个名叫”slider”的东西即可,不用操心他依赖什么,更不用管如何引入到页面中,yui都帮我们搞定:

<script>
TB.addmoudle({
___logicA:{
______fullpath:’logica.js’,
______requires:['slider']
___}
}).use(‘logicA’,function(Y){
___LogicA.start();
});
</script>

当我们看最终组成的页面的时候,看到的只是埋藏在页面各个角落的这些简短的结构一致的js代码段。很易理解,这点代码也不用像长的代码块压成一行。(更多细节可参照 前端弱架构导致的代码污染 )

5,颗粒化 or http请求数
这的确是一对矛盾,颗粒化带来了项目开发、管理、和代码重用的高效率,却又引入了更多的http请求数,好在yui提供了combo,可以将所有的http请求合并成一个。只需在YUI引入的时候配置下combo属性即可,高颗粒化的请求数瞬间降低一倍以上。在之前做雅虎关系的时候,在yui2和yui3pre并存的情况下,可以将请求降低到4个,yui2和3各一个种子,各自一个combo。当然这是在hack掉yui的loader的前提下。yui默认不会合并非yui文件(更多细节可以阅读基于yui的团队开发)。即使这样,我们仍然可以控制我们的http请求数,在不hack yui的情况下,可以解决部分性能问题。

6,懒惰加载 or 即时加载即时执行
上文提到,逻辑依赖沙箱,沙箱依赖的js文件则是延时加载的,这样就导致一个问题,当页面比较庞大的时候,会等待页面js加载完毕才会渲染动作,这样的用户体验不佳,而即时加载即使运行则可以渲染出模块后随即渲染动作,当网速一定的时候,两者看似是一对不可调和的矛盾,yui 动态加载的机制比较折中的处理了这个问题,A逻辑需要a.js,B逻辑需要b.js,A逻辑则只会在a.js加载完成后执行,而不管b.js是否加载完成,而当A需要a.js和b.js的时候,A则需要等待a.js和b.js都加载完成才会执行,B逻辑只需判断当前是否已经加载b.js,如果b.js已经在其他模块中引入进来,B则可以立即执行。但确定的是,所有的js的引入一定是在domReady后执行的,也就是说,不管怎样,动作的渲染一定是在页面html结构出来后才开始执行的,用户体验上还是会有损失。

7,面向接口的设计 or 面向dom的设计
我们知道jquery的插件习惯将所有的动作都加载到一个$(‘#id’)上,使用的时候只要执行类似$(‘#id’).init()即可。这看起来简洁明快,开发者的逻辑的思路也始终没有离开“节点”,很方便理解,而对yui3 的node扩展就不那么方便,从yui3的pre版到正式版,对node扩展的方法在不断的修改(更多细节看这里:扩展yui3 node的定时器),这也可以看出yui设计者在对node扩展性设计时的纠结和苦恼:要不要允许开发者去扩展node节点呢?大概是因为设计者们对prototype先天的弊端心有余悸。目前看来,设计者还没有完全走出纠结,尽管对node扩展相比yui3第一个预览版方便了很多,开发者仍然不能像写jquery插件那样优雅自如的对node进行扩展。相反,zakas却将更多的精力放在了widget接口的设计上,在这一点上,相比jquery,yui3则具有无可限量的优越性,因为在yui3中,组件不仅仅是组件,而是一个有血有肉的生命体,他可以出生,可以成长,可以被改造,可以死亡,组件在这些复杂的运行时环境中自我锤炼,因此,一个复杂页面在yui3的技术体系中,变成了一个由无数组件链接而成的生态系统,这种生物链所带来的设计创新和新视野是其他js框架无论如何也无法超越的。关于yui3的组件开发更多细节可以参照:基于yui3的组件开发1 和 克军在D2上的分享《从yui2到yui3看前端的演变》

8,苗条的身材 or 庞大的身躯
说到这里,大概会有很多人拍砖。其实jquery和yui同属两类不同的js框架,一个苗条纤细,一个身重如山,两者之间其实没有什么水深火热,只是使用范围不同罢了,类似jquery的轻框架的使用范围是博客级别的小网站,尤其适合单人开发,代码写一次不再修改,而且很适合初学者学习使用,给初学者带来自信。yui则使用与企业级的项目中的团队开发,项目维护周期远远超过开发周期,因此yui性能一定比不过jquery,jquery的续航能力也一定不如yui,没有最优秀,只有最适合。当然这自然也挡不住我个人对迷人的jquery的喜爱,只要我们能从各个js框架学到东西,能提高自己做前端架构的能力,就ok。

说了这么多,其实只有一个观点,人无完人,框架无完框架,缺憾之处必有权衡。以上YY,欢迎拍砖!

 

引:http://ued.taobao.com/blog/2010/01/yui3%E8%AE%BE%E8%AE%A1%E4%B8%AD%E7%9A%84%E6%BF%80%E8%BF%9B%E5%92%8C%E5%A6%A5%E5%8D%8F/

分享到:
评论

相关推荐

    yui3-master.zip

    本文将围绕“yui3-master.zip”这个压缩包,深入探讨YUI3的核心概念、结构和实际应用。 1. **模块化设计** YUI3采用了模块化的设计理念,每个功能都被封装为独立的模块,开发者可以根据需要按需加载,降低了整体...

    YUI3 中tree的两种实现

    这篇博文“YUI3 中tree的两种实现”探讨了如何在YUI3中创建和管理树形结构。 1. **YUI3 TreeView组件** YUI3 TreeView组件是YUI3核心库的一部分,它允许开发者创建交互式的树结构。这个组件支持节点的添加、删除、...

    从YUI2到YUI3看前端的演变 pdf

    YUI3 引入了粒度更细的模块管理方式,通过异步 HTTP 请求加载模块、然后执行回调来加载和使用模块。现场有很多人提出疑问,大家无非关心的是“效率”二字。个人以为在现阶段,这种方式有一点激进,否能为广大用户所...

    YUI3 dialog组件

    Dialog组件是YUI3中的一个重要部分,它允许开发者创建可交互的弹出窗口,常用于提示信息、确认操作、展示详细内容等场景。 ### 1. Dialog组件的基本结构 Dialog组件由几个关键部分组成: - **容器(Container)**...

    yui3-3.17.2最新版

    在YUI 3中,主要强调了模块化和轻量化设计,它采用了CommonJS规范,允许开发者按需加载所需的功能,降低了页面的加载时间。YUI 3包含了一系列核心模块,如Event(事件处理)、Node(DOM操作)、IO(异步数据交互)等...

    YUi文档(中文的哦)

    YUI模块作为YUI3中的单一核心模块,它充当了整个框架的基础。所有使用YUI3的页面都需要包含这个核心模块,以便能够动态地加载所需的其他模块及其依赖项。 - **YUI实例**: 每个页面可以共享一个YUI实例,也可以根据...

    yui 资源包

    在3.9.0 r2这个版本中,YUI提供了丰富的组件和工具,帮助开发者创建高效、可维护且用户体验优良的Web应用。 一、YUI的核心特性 1. **模块化**:YUI采用AMD(Asynchronous Module Definition)模块加载机制,允许...

    YUI3.6文档及示例

    1. **模块系统**:YUI3引入了模块化设计,允许开发者按需加载组件,降低页面的初始化时间。模块可以通过`YUI.use()`方法来加载,实现了代码的异步加载和依赖管理。 2. **事件系统**:YUI的事件处理机制强大且灵活,...

    从YUI2到YUI3看前端的演变

    从YUI2到YUI3看前端的演变

    yui.rar 例子

    在Web开发中,布局设计是至关重要的,YUI提供了一套完整的布局解决方案,如Grids CSS框架,可以轻松实现响应式设计,适应不同屏幕尺寸和设备。在这个例子中,左中右三个模块的划分,正是通过YUI的Container组件和...

    yahoo3.0 YUI Examples

    5. **响应式设计支持**:YUI 3支持响应式设计,能够适应不同设备和屏幕尺寸,提高了跨平台兼容性。 6. **数据绑定和Model-View-Controller (MVC)**:YUI 3提供了解耦数据和视图的机制,使得应用更易于维护和扩展。 ...

    YUI3 完整包

    Yahoo! UI Library (YUI) 是一个开放源代码的 JavaScript 函数库,为了能建立一个高互动的网页,它采用了AJAX, DHTML 和 DOM 等程式码技术。它也包含了许多 CSS 资源。

    YUI3.7.3 最新版本 带API

    9. **响应式设计支持**:YUI3包含了一些工具,如Resize Utility,帮助开发者实现响应式设计,使应用在不同设备和屏幕尺寸上都能良好运行。 10. **可定制性**:YUI3允许开发者根据项目需求选择需要的模块,通过构建...

    Yahoo YUI2.7中文API 完整版

    4. **事件处理**:YUI 提供了一套完善的事件系统,可以方便地监听和处理页面中的各种事件,如点击、滚动、键盘输入等。 5. **AJAX 支持**:通过 Connection Manager 提供 AJAX 功能,允许异步与服务器进行通信,...

    经典的YUI 示例中文文档

    在YUI的某些版本中,`YAHOO.lang.extend`和`YAHOO.extend`指向同一个函数对象。 - **`zlang.augment`**:将一个对象的部分或全部属性复制到另一个对象中,但这种复制仅是浅拷贝,即只复制引用而非实际创建新对象。...

    YUI中文文档CHM

    YAHOO YUI 中文文档 AJAX 详细 比较好用

    YAHOO YUI3简单入门

    YUI3是YUI的第三个主要版本,它在设计时注重模块化、可扩展性和性能优化,提供了一系列用于处理DOM操作、事件处理、动画效果、Ajax通信、数据存储等任务的工具。本教程将带你入门YUI3的基础知识。 **模块化设计** ...

    YAHOO yui2.7 文档+ 代码+例子

    YUI的设计非常注重模块化和可扩展性,开发者可以通过编写新的模块来扩展其功能。YUI的模块化结构使得代码组织清晰,易于维护。 **3. 文档和示例** YUI 2.7提供的文档详尽介绍了每个组件的用法,包括API参考、教程和...

    《YUI使用文档》汉语版的yui学习材料

    《YUI使用文档》汉语版是一份详细的YUI学习材料,它涵盖了这个JavaScript库的核心功能和使用方法。YUI,全称Yahoo! User Interface Library,是Yahoo开发的一个开放源代码的JavaScript库,旨在帮助开发者创建交互式...

Global site tag (gtag.js) - Google Analytics