SeaJS在AIFISH前端框架中的使用详解
Posted 麒麟敏捷社区
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SeaJS在AIFISH前端框架中的使用详解相关的知识,希望对你有一定的参考价值。
背景描述
在软件开发过程中,模块化编程思想已经习以为常了,模块化编程不仅仅给开发团队带来效率方面上的好处,还能够让开发的项目或者产品维护成本大大降低。
那么,在WEB开发过程中JS脚本语言已经不可或缺了,通过JS脚本语言能够带来更加舒适的人机交互和用户体验。但是,JS脚本的使用过程中也会有出现引用依赖的混乱,那么JS脚本语言的模块化思想势必会得到大家广泛的认可,在这样的一个背景下,AIFISH框架采用了由现蚂蚁金服前端工程师玉伯带来的成熟的模块化加载js框架——seajs。
SeaJS简介
Seajs,一个Web模块加载框架,追求简单、自然的代码书写和组织方式,Sea.js 遵循 CMD 规范,模块化JS代码。依赖的自动加载、配置的简洁清晰,可以让程序员更多地专注编码。
优点:
1. 提高可维护性。
2.模块化编程。
3.动态加载,前端性能优化
这里不得不提一下AMD和CMD规范:
异步模块定义(AMD)是AsynchronousModule Definition的缩写,是 RequireJS 在推广过程中对模块定义的规范化产出。
通用模块定义(CMD)是Common ModuleDefinition的缩写,是SeaJS 在推广过程中对模块定义的规范化产出。
RequireJS和 SeaJS 都是模块化框架的代表,AMD和CMD,是他们各自定义模块化的方式,大同小异,主要是代码风格和API不同。
SeaJS使用
模块化?何为模块化?在seaJS中的所有javascript都必须要依据模块化的书写格式。这又是什么意思?其实,seaJS在管理文件的过程中是根据javascript(这里我们先讨论seaJS对javascript的管理)的文件名进行管理的,这个文件名就相当于我们平时所说的命名空间。在调用文件的时候我们可以直接写文件名而不需要写它的后缀。但是也是有特殊情况的:
a.加载css的时候一定要加后缀的
b.路径中有”?“的时候javascript文件的后缀不能省略
c.路径中是以"#"号结尾的文件也不可以省去后缀
到底如何模块化一个javascript?这个时候就要用到我们seaJS提供的几个接口了,模块化使用define函数,如下:
define(id,deps,factory)
id:模块id,可以自己赋值,如果不赋值默认就是该函数的相对路径,各位可以调试看看;
deps:当前模块所依赖的模块,这里关键就是按需加载了,将你需要的js文件引入;
factory:模块工厂函数,这个函数是重点,主要是模块的逻辑实现。
在前端开发领域,一个模块,可以是JS 模块,也可以是 CSS 模块,或是 Template 等模块。在 Sea.js 里,我们专注于 JS 模块(其他类型的模块可以转换为 JS 模块):
1.模块是一段 JavaScript 代码,具有统一的基本书写格式。
2.模块之间通过基本交互规则,能彼此引用,协同工作。
在AIFISH前端框架中每个js文件都是一个模块,在文件开头有如下定义:
factory
为函数时,表示是模块的构造方法。执行该构造方法,可以得到模块向外提供的接口。factory
方法在执行时,默认会传入三个参数:require
、exports
和 module
。
当前模块对外提供的接口。传给 factory
构造方法的 exports
参数是 module.exports
对象的一个引用。只通过 exports
参数来提供接口,有时无法满足开发者的所有需求。 比如当模块的接口是某个类的实例时,需要通过 module.exports
来实现。
require
是一个方法,接受模块标识作为唯一参数,用来获取其他模块提供的接口。之后就可以在当前js模块引用utils模块的方法了。
SeaJS踩坑全记录
seajs的模块定义方式非常simple,主要的难点在于不同项目有不同的部署要求,因此因为模块标识理解不够在AIFISH前端开发框架选型初期造成各种坑。下面详细分析下模块标识和加载机制!
模块标识命名规则
1、一个模块标识由斜线(/)分隔的多项组成。
2、每一项必须是小驼峰字符串、 . 或 .. 。
3、模块标识可以不包含文件后缀名,比如 .js 。
4、模块标识可以是 相对 或 顶级 标识。如果第一项是 . 或 ..,则该模块标识是相对标识。
解释一下其中的几种概念:
1、相对路径,以. 或 ..开头。
2、顶级路径,不以.或 ..及斜线(/)开头。
3、普通路径,除相对和顶级路径外的,比如/(根路径)开头的,"http://"、"https://"、 "file:///" 等协议标识开头的。
4.模块命名空间是seajs所在文件的根路径即所谓的base路径,去除了seajs/x.y.z 字串, 也可以指定seajs.config({base:});
模块依赖提取过程如何解析
1、只提取相对标识。
2、相对标识相对 require 所在模块的标识来解析。
上线后模块标识解析规则
1、顶级标识始终相对 base 基础路径解析。(顶级标识由字符串开头)。
3、模块定义中require 和 require.async 的相对路径相对当前模块路径来解析。
如果我们能理解其模块标识解析设计的出发点,那么就可以轻易的理解这些而不用记忆这么多:
1、关注度分离。书写模块的时候我们是不用指定模块id的,require的模块时候只要填入依赖模块的相对路径,于是我们只要关注代码的书写而不是依赖,打包后工具会自动帮我们处理好模块id。
2、尽量与浏览器的解析规则一致。上线后在浏览器中的代码,模块路径的解析规则应该于平时用的css、js这些加载路径规则一样,普通路径和相对路径的都是相对当前页面的。
千万别天真的以为你在模块里面这样:
就天真地以为,这个模块会加载完a模块之后再加载b模块。真相其实是这样的:
在一个模块里面,require语句的优先级是最高的,无论你将它放在模块的任意位置会优先执行require。 注意,优先执行require不代表你可以这么写:
除非a.js是个三方插件或者a模块不对外提供任何方法和属性,仅仅是用于给页面来点特效啦,加载一些数据啦等,和代码的下文没有什么关系的事情,你大可以把require(“a”)放在任何地方,也就没必要将其赋值给某个变量了。
比如:
a.js的内容如下:
一个依赖a模块的模块内容如下:
执行结果你会发现弹窗内容果然先是”a”,后是”t”;
值得注意的是seajs还有一种模块加载方法是use,它的加载时机就得看你把它写在什么地方了。
接上文的那个依赖a模块的模块内容如果是这么写:
这次的执行结果就是先”t”后”a”了。
言归正传,a和b到底谁先加载,我可以肯定地告诉你,确实是a先加载,但是!恩,但是来了。但是a和b谁先加载完就得看各自的造化了,或是因为网络原因,或是因为文件大小,意思就是说你require的模块它们之间一定不要有啥耦合关系,否则很有可能会因为加载的先后顺序导致一些异常,不过话又说回来,如果你严格按照seajs的规范来设计模块的话这种事问题肯定不会出现的,各个模块内部都有独立的作用域和其明确的依赖链。
总 结
AIFISH中使用SeaJS可以提高JavaScript代码的可读性和清晰度,解决目前JavaScript编程中普遍存在的依赖关系混乱和代码纠缠等问题,方便代码的编写和维护。
SeaJS本身遵循KISS(Keep It Simple, Stupid)理念进行开发,其本身仅有个位数的API,因此学习起来毫无压力。在学习SeaJS的过程中,处处能感受到KISS原则的精髓——仅做一件事,做好一件事。
以上是关于SeaJS在AIFISH前端框架中的使用详解的主要内容,如果未能解决你的问题,请参考以下文章