YUI3设计中的激进和妥协

相信每个前端工程师都有自己喜爱的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,欢迎拍砖!

时间: 2024-12-04 20:33:28

YUI3设计中的激进和妥协的相关文章

yui3在框架设计中的牺牲和让步

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

交互设计在产品设计中的工作流程小议

当产品的用户体验要求越来越高时,交互设计师的职责也越来越明晰了.交互设计师除了自身的基本功外,还需要有一个规范的流程,才能够使工作完整有序. 图1 交互设计在产品设计中的流程图 一.版本计划 版本计划是指在产品或项目立项时,对产品的一个总的规划,通常包括产品的需求与目标,比如能够实现哪些功能,性能上如何.这一过程,交互很少直接参与,或者列席一下发版立项,对计划情况有所知晓.交互可以纵观一下历史版本,对比行业内外的相关产品,以及满怀未来产品的一种期待:实用.方便.美观-- 二.需求分析 在版本计划

交互设计中的5项视觉指导原则

  视觉是人的第一感观,它在影响用户行为方面起着决定性作用,视觉信息对产品的交互产生了深远影响. 来自UXPin的Jerry Cao,通过本文向我们解释了如何保持视觉与交互的协调. 我不想贬低文字的重要性,但也不想忽视视觉.两者是同等重要的交互设计元素.文字就是交互,但那些视觉元素(比如图标.菜单.图像等)才是用户实际上操作的东西.虽然有些可用性专家会提及Craigslist甚至Amazon,作为丑陋但可用(而且受欢迎)的网站案例.但毫无疑问,美感总会有所帮助. 情感是用户体验的关键:视觉设计优

网站BANNER设计中 中英文字体的结构分析

本来想写"Advertisemen中的字体结构分析",后来发现这个标题写得有点大,偏离了在目前工作中的针对性,因此缩小到banner的范围,以下内容仅个人在目前工作中对banner设计上的一点浅见,仅起抛砖引玉的作用. Banner的传达方式 [TOPIC] 针对网站中的banner Banner的本身形状:形状决定了其固定的构成方式,一般为矩形,横幅,左右结构和居中; Banner的文字特点:主题式,一般分为主标题和副标题,文字较多;设计的时候还需要考虑应用到网站各种尺寸推广图的可读

网页设计中该如何决定是否使用框架

框架的最常见用途就是导航.一组框架通常包括一个含有导航条的框架和另一个要显示主要内容页面的框架. 但是,框架的设计可能比较复杂;并且在许多情况下,您可以创建没有框架的Web页,它可以达到使用一组框架所能达到的许多同样效果.例如,如果您想让导航条显示在页面的左侧,则既可以用一组框架代替您的页面,也可以只是在站点中的每一页上包含该导航条;下图显示了具有类似框架布局的页面设计,但在设计中并没有使用框架. 类似框架布局的页面设计 许多专业Web设计人员不喜欢使用框架,并且许多浏览Web的人也不喜欢框架.

数据库设计中的14个技巧

1. 原始单据与实体之间的关系  可以是一对一.一对多.多对多的关系.在一般情况下,它们是一对一的关系:即一张原始单据对应且只对应一个实体.在特殊情况下,它们可能是一对多或多对一的关系,即一张原始单据对应多个实体,或多张原始单据对应一个实体.这里的实体可以理解为基本表.明确这种对应关系后,对我们设计录入界面大有好处.  [例1]:一份员工履历资料,在人力资源信息系统中,就对应三个基本表:员工基本情况表.社会关系表.工作简历表.这就是"一张原始单据对应多个实体"的典型例子.  2. 主键

网站设计中如何将对应的用户网页的数据保存在数据库中

问题描述 网站设计中如何将对应的用户网页的数据保存在数据库中 最近在做一个关于二手书交易平台的小项目(毕业设计),在处理用户登录后自动跳转到所对应的用户个人网页时没什么思路,求各位大神指点一下...小妹初来乍到,不甚感激啊... 解决方案 并不是直接把用户的网页保存在数据库中,而是把用户的信息存在各张数据表中.在用户登陆后可以获取到用户的ID(确保是唯一的),根据这个ID获取数据表中用户的相关信息,然后在用户个人页面进行展示..比如表A是用户表,其主键为user_id,同时user_id为表B的

语言设计中的鸭子类型风格

      在动态语言的世界里一直流传着一种叫做鸭子类型的风格,其来自谚语:"如果行鸭子一样走路,像鸭子一样呱呱叫,那它就是一只鸭子".      从鸭子类型,我们可以联想到它的推导,并不在乎类型的真正实体,只要他的行为有鸭子的特性,那么我们就可以把它当做一只鸭子来看到.在动态语言设计中,可以解释为无论一个对象是什么类型的,只要它具有某类型的行为(方法),则它就是这一类型的实例,而不在于它是否显示的实现或者继承.      鸭子类型在动态语言中被广为奉行.某类接口需要一个log接口,换

APP设计中便捷的单手操作

  探讨APP的手势操作前,我想先介绍两篇文章来了解用户是如何使用手机的,以及触控屏是如何来感应我们的操作的. 用户是如何使用手机的 Steven Hoober在<How Do Users Really Hold Mobile Devices?>[1]一文中指出,通过两个月的时间对1333名手机用户在公众场所(街道.机场.汽车站.咖啡馆.火车上.汽车上等)使用习惯的观察得出以下结论: ①780名用户是通过滑动.点击.打字等来操作屏幕,其他用户则仅仅是用手机来收听.观看.打电话. ②49%的用户