|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
iOS5开始支持CoreImage了还没去看Mac上的CI是很强大的CFNetwork---从来没用过我一般都会用ASIHttpRequset封装好的高层网络库OBJC实现的CFNetwork好像是C实现CoreLocation---获取位置的库工具很少在计划思绪篇中,已对AMD在计划上的一些思索做了对照具体的叙述。以是这一篇只会提一些倡议,援用一些计划思绪篇中的结论,不会再具体形貌为何。
本篇提出的一切倡议,都是针关于开辟时就利用AMD的弄法。据我所知,有一些团队在开辟时依照CommonJS的体例编写模块,经由过程开辟时工具监听文件变更及时编译,上线前经由过程工具构建,AMD地道被看成模块包装来用。本篇提出的倡议不涵盖这类使用场景。
部分倡议有必定的堆叠,大概来由是不异的。触类旁通才能较强的浏览者大概会以为我很罗嗦,包涵。
开辟时
模块声明不要写ID
将模块ID交给使用页面决意,便于重构和模块迁徙。模块开辟者应当顺应这点,从模块界说时就决意模块称号的思绪中束缚出来。这是利用AMD的开辟者能取得的最年夜便当。
- //gooddefine(function(require){varsidebar=require(./common/sidebar);functionsidebarHideListener(e){}return{init:function(){sidebar.on(hide,sidebarHideListener)sidebar.init();}};});//baddefine(main,function(require){varsidebar=require(./common/sidebar);functionsidebarHideListener(e){}return{init:function(){sidebar.on(hide,sidebarHideListener)sidebar.init();}};});
复制代码
模块分别应尽量细粒度
细粒度分别模块,有助于更精密地举行模块变动、依附、按需加载和援用等方面的办理,有益于让体系布局更明晰,让计划上的成绩延迟表露,也能从必定水平上制止一些看起来也公道的轮回依附。
举个例子:在namespace形式下我们大概将一些utilfunction经由过程method体例表露,在AMD模块分别时,应当拆分红多个模块。
- //good:分红多个模块define(function(){functioncomma(){}returncomma;});define(function(){functionpad(){}returnpad;});//baddefine(function(){return{comma:function(){},pad:function(){}};});
复制代码
在factory中利用require援用依附模块,不要写dependencies参数
必要啥就在以后地位require一个,然后即刻利用是最便利的。当模块文件对照年夜的时分,我想没有谁会喜好回到头部在dependencies中增加一个依附,然后在factory里增加一个参数。
别的,只利用dependencies参数声明依附的体例,办理不了轮回依附的成绩。为了项目中模块界说体例的分歧性,也应当一致在factory中利用require援用依附模块。
- //gooddefine(function(require){varsidebar=require(./common/sidebar);functionsidebarHideListener(e){}return{init:function(){sidebar.on(hide,sidebarHideListener)sidebar.init();}};});//baddefine([./common/sidebar],function(sidebar){functionsidebarHideListener(e){}return{init:function(){sidebar.on(hide,sidebarHideListener)sidebar.init();}};});
复制代码
关于要利用的依附模块,即用即require
恪守即用即require的准绳有以下缘故原由:
- require与利用的间隔越远,代码的浏览与保护本钱越高。
- 制止偶然义的装载时依附。在计划思绪篇中有提到:关于轮回依附,只需依附环中任何一条边是运转时依附,这个环实际上就是活的。假如全体边都是装载时依附,这个环就是逝世的。恪守即用即require能够无效制止呈现逝世轮回依附。
- //gooddefine(function(require){returnfunction(callback){varrequester=require(requester);requester.send(url,method,callback);};});//baddefine(function(require){varrequester=require(requester);returnfunction(callback){requester.send(url,method,callback);};});
复制代码
关于package依附,require利用Top-LevelID;关于不异功效模块群组下的依附,require利用RelativeID
这条的来由与模块声明不要写ID不异,都是为了取得AMD供应的模块天真性。
- //gooddefine(function(require){var_=require(underscore);varconf=require(./conf);return{}});//baddefine(function(require){var_=require(underscore);varconf=require(conf);return{}});
复制代码
不异功效模块群组的界定必要开辟者本人分辩,这取决于你对将来变动大概性的判别。
上面的目次布局分别中,假定加载器的baseUrl指向src目次,你能够以为src下是一个不异功效模块群组;你也能够以为common是一个不异功效模块群组,biz1是一个不异功效模块群组。假如是后者,biz1中模块对common中模块的require,可使用RelativeID,也能够利用Top-LevelID。
可是不管怎样,common或biz1中模块的互相依附,应当利用RelativeID。
- project/|-src/|-common/|-conf.js|-sidebar.js|-biz1/|-list.js|-edit.js|-add.js|-main.js|-dep/|-underscore/|-index.html
复制代码
模块的资本援用,在factory头部声明
偶然候,一些模块必要依附一些资本,罕见一个营业模块必要依附响应的模板和CSS资本。这些资本必要被加载,可是在模块外部代码中其实不必定会利用它们。把这类资本的声明写在模块界说的入手下手部分,会更明晰。
别的,为了便于重构和模块迁徙,关于资本的援用,resourceID也应当利用RelativeID的情势。
- define(function(require){require(css!./list.css);require(tpl!./list.tpl.html);varAction=require(er/Action);varlistAction=newAction({});returnlistAction;});
复制代码
不要利用paths
在计划思绪篇中有说到,默许情形下paths是绝对baseUrl的,设置了paths时分歧ID的模块大概对应到统一个define文件。在一个体系里,统一个文件对应到多个模块,这类二义很简单招致难以了解的,而且会留下坑。
- //badrequire.config({baseUrl:src,paths:{conf:common/conf}});
复制代码
那paths在甚么中央用到呢?在打包构建章节会有一些申明。
利用第三方库,经由过程package引进
一般,在项目里会用到一些第三方库,除非你一切工具都本人完成。就算一切工具都本人完成,基本的营业有关部分,也应当作为自力的package。
一个倡议是,在项目入手下手就应当计划优秀的项目目次布局,在这个时分断定package的寄存地位。一个项目标源代码应当放在一个自力目次下(好比叫做src),这内里的一切文件都是和项目营业相干的代码。寄存第三方库package的目次应当和项目源代码目次分隔。
- project/|-src/|-common/|-conf.js|-sidebar.js|-biz1/|-list.js|-edit.js|-add.js|-main.js|-dep/|-underscore/|-index.html
复制代码
假如有大概,界说一种package目次构造的标准,本人开辟的package都依照这个体例构造,用到的第三方库也依照这类体例做一个包装,便于经由过程工具举行package的办理(导进、删除、package间依附办理等)。
- 申明:源代码不依照CommonJS倡议放在lib目次的缘故原由是,nodepackage是放在lib目次的,frontendpackage应当有所辨别。package/|-src/|-doc/|-test/|-package.json
复制代码
告白工夫来了:
EFE手艺团队在决意利用AMD后,就即刻标准了项目目次布局和package布局。这是我们以为对照公道的体例。我们利用了良多业内的尺度和工具(CommonJSPackage/Semver等),在此之上做一些前端使用的细化,具有通用性,其实不专门为我们的项目特性定制,实行的过程当中也一向对照顺遂。我们厥后基于此也搭建了外部的npm作为package公布平台,开辟的EDP也包括了项目中利用和办理package功效。但愿能给开辟者,出格是地点团队还没有做响应事情的开辟者,一些参考和启示。
营业反复的功效汇合,赶早抽取package
这和尽早重构是一个事理。那末,甚么样的工具必要被抽取成package呢?
- 假如项目营业有关的基本库或框架是本人开辟的,那一入手下手就应当作为package存在。
- 营业大众代码通常为不必要抽取成package的。
- 一些营业大众模块集,假如预期会被其他项目用到,就应当抽取成package。举个例子,正在开辟的项目是面向PC的,项目中有个数据会见层,假如以后还要做Mobile的版本,这个数据会见层就应当笼统成package。
package外部模块之间的项目依附,require利用RelativeID
package外部模块之间的依附经由过程RelativeIDrequire,可以包管package外部封装的全体性。在AMD情况下,package利用者大概会必要多版本并存,大概在项目中依据本人的喜欢对引进的package定名(好比xxui,利用者大概会希冀在项目里利用时,package称号就叫做ui)。
- //good:分红多个模块define(function(){functioncomma(){}returncomma;});define(function(){functionpad(){}returnpad;});//baddefine(function(){return{comma:function(){},pad:function(){}};});0
复制代码
package外部模块对主模块的依附,不利用require(‘.’)
package开辟者会指定一个主模块,一般主模块就叫做main。package内其他模块对它的依附可使用require(‘.’)和require(‘./main’)两种体例。
可是,我们没法扫除package的利用者在设置package的时分,以为把别的一个模块作为主模块更便利,从而举行了非支流的设置。
- //good:分红多个模块define(function(){functioncomma(){}returncomma;});define(function(){functionpad(){}returnpad;});//baddefine(function(){return{comma:function(){},pad:function(){}};});1
复制代码
利用require(‘./main’)就可以躲避这个成绩。以是,不要利用require(‘.’)。
能够对情况和模块举行辨别,不必要太强制症
有的第三方库,自己更合适作为情况引进,基础上项目一切模块开辟时分城市以这些库的存在为条件。如许的工具就更合适作为情况引进,纷歧定非要把它看成模块,在每一个模块中require它。
典范的例子有es5-shim/jquery等。
间接作为情况引进的办法是,在页面中,在引进Loader的script前引进。
- //good:分红多个模块define(function(){functioncomma(){}returncomma;});define(function(){functionpad(){}returnpad;});//baddefine(function(){return{comma:function(){},pad:function(){}};});2
复制代码
打包构建
构建工具
r.js是RequireJS附带的optimize工具,对照成熟,打包构建AMD模块的构建产品优异。
Grunt和Gulp下的一些AMD构建插件,有的用了r.js,有的是本人写的,构建产品的质量乱七八糟,选用之前能够看看。我以为以下几点能够判别构建产品是不是优异:
- ID被固化
- factory中require的依附被提取添补到dependencies
- RelativeID的require,不必要在构建阶段normalize
- factory没有举行任何修正,包含参数和函数体
- 对package的主模块举行了处置
我们团队开辟的EDP中,AMD模块构建就是本人写的。假如想本人完成AMD模块的构建,下面的几点和EDP都有必定的参考代价。
可是,在我所晓得的AMD构建工具中,都必要经由过程设置,手工指定哪些模块必要兼并,兼并的时分exclude哪些模块,include哪些模块。还没有一个工具可以很好的剖析体系,主动举行对照优化的构建。我们在这方面有一些堆集,可是理论的效果尚不明白,以是就不说了。
即便在构建阶段,把一切的模块界说都兼并到主模块的文件中,构建计划仍是必要将散模块独自构建天生独自的文件。在多页面临模块交织援用,或按需加载时,会对照有匡助。
CDN
由于功能的思索,线上情况静态资本经由过程CDN分发是一种经常使用做法。此时,静态资本和页面处于分歧的域名下,线上情况的Loader设置必要经由过程paths,让Loader可以准确加载静态资本。
- //good:分红多个模块define(function(){functioncomma(){}returncomma;});define(function(){functionpad(){}returnpad;});//baddefine(function(){return{comma:function(){},pad:function(){}};});3
复制代码
假如一切的模块都全体经由过程CDN分发,能够间接指定baseUrl。
- //good:分红多个模块define(function(){functioncomma(){}returncomma;});define(function(){functionpad(){}returnpad;});//baddefine(function(){return{comma:function(){},pad:function(){}};});4
复制代码
开辟情况和线上情况的设置信息差别,依据DRY准绳,这个事情必定要用工具在构建历程主动完成。
利用内容择要作为文件名的弄法
在构建历程,利用文件内容的择要作为文件名,是一种经常使用的优化手腕。这类体例可以在HTTP层面设置强cache,让用户可以最年夜水平缓存,削减收集传输的流量和工夫。
可是在AMD中,模块ID与路径应当是一个对应干系。怎样破?这里供应两种弄法:
第一种体例:将打包后的模块界说兼并文件,间接在页面上经由过程script标签引进。
- //good:分红多个模块define(function(){functioncomma(){}returncomma;});define(function(){functionpad(){}returnpad;});//baddefine(function(){return{comma:function(){},pad:function(){}};});5
复制代码
第二种体例:经由过程paths设置映照。
- //good:分红多个模块define(function(){functioncomma(){}returncomma;});define(function(){functionpad(){}returnpad;});//baddefine(function(){return{comma:function(){},pad:function(){}};});6
复制代码
在一个Web使用,出格是范围较年夜的Web使用中,为了功能最优化的思索,大概会两种体例分离着玩:
很少去思考,没有去多问几个为什么。这是学习的大忌,我认识到了自己学习方法上的错误。孔子说,学而不思则罔,思而不学则殆。一点也没错,学和思是要结合的,这样才能进步。现在回想一下,我学到了什么?自己也无言以对了。 |
|