第四课:seajs的模块编译_compile过程
最近比较闲,我就讲下seajs的模块编译_compile过程。
这里紧接着第三课的例子来讲解。首先是a.js的编译
Module.prototype._compile = function() {
126 var module = this
127 // 如果该模块已经编译过,则直接返回module.exports
128 if (module.status === STATUS.COMPILED) {
129 return module.exports
130 }
133 // 1. the module file is 404.
134 // 2. the module file is not written with valid module format.
135 // 3. other error cases.
136 // 这里是处理一些异常情况,此时直接返回null
137 if (module.status < STATUS.SAVED && !hasModifiers(module)) {
138 return null
139 }
140 // 更改模块状态为COMPILING,表示模块正在编译
141 module.status = STATUS.COMPILING
142
143 // 模块内部使用,是一个方法,用来获取其他模块提供(称之为子模块)的接口,同步操作
144 function require(id) {
145 // 根据id解析模块的路径
146 var uri = resolve(id, module.uri)
147 // 从模块缓存中获取模块(注意,其实这里子模块作为主模块的依赖项是已经被下载下来的)
148 var child = cachedModules[uri]
149
150 // Just return null when uri is invalid.
151 // 如果child为空,只能表示参数填写出错导致uri不正确,那么直接返回null
152 if (!child) {
153 return null
154 }
155
156 // Avoids circular calls.
157 // 如果子模块的状态为STATUS.COMPILING,直接返回child.exports,避免因为循环依赖反复编译模块
158 if (child.status === STATUS.COMPILING) {
159 return child.exports
160 }
161 // 指向初始化时调用当前模块的模块。根据该属性,可以得到模块初始化时的Call Stack.
162 child.parent = module
163 // 返回编译过的child的module.exports
164 return child._compile()
165 }
166 // 模块内部使用,用来异步加载模块,并在加载完成后执行指定回调。
167 require.async = function(ids, callback) {
168 module._use(ids, callback)
169 }
170 // 使用模块系统内部的路径解析机制来解析并返回模块路径。该函数不会加载模块,只返回解析后的绝对路径。
171 require.resolve = function(id) {
172 return resolve(id, module.uri)
173 }
174 // 通过该属性,可以查看到模块系统加载过的所有模块。
175 // 在某些情况下,如果需要重新加载某个模块,可以得到该模块的 uri, 然后通过 delete require.cache[uri] 来将其信息删除掉。这样下次 使用时,就会重新获取。
176 require.cache = cachedModules
177
178 // require是一个方法,用来获取其他模块提供的接口。
179 module.require = require
180 // exports是一个对象,用来向外提供模块接口。
181 module.exports = {}
182 var factory = module.factory
183
184 // factory 为函数时,表示模块的构造方法。执行该方法,可以得到模块向外提供的接口。
185 if (util.isFunction(factory)) {
186 compileStack.push(module)
187 runInModuleContext(factory, module)
188 compileStack.pop()
189 }
190 // factory 为对象、字符串等非函数类型时,表示模块的接口就是该对象、字符串等值。
191 // 如:define({ "foo": "bar" });
192 // 如:define('I am a template. My name is {{name}}.');
193 else if (factory !== undefined) {
194 module.exports = factory
195 }
196
197 // 更改模块状态为COMPILED,表示模块已编译
198 module.status = STATUS.COMPILED
199 // 执行模块接口修改,通过seajs.modify()
200 execModifiers(module)
201 return module.exports
202 }
if (util.isFunction(factory)) {
186 compileStack.push(module)
187 runInModuleContext(factory, module)
188 compileStack.pop()
189 }
这里就是把module.export进行初始化。runInModuleContext方法:
// 根据模块上下文执行模块代码
489 function runInModuleContext(fn, module) {
490 // 传入与模块相关的两个参数以及模块自身
491 // exports用来暴露接口
492 // require用来获取依赖模块(同步)(编译)
493 var ret = fn(module.require, module.exports, module)
494 // 支持返回值暴露接口形式,如:
495 // return {
496 // fn1 : xx
497 // ,fn2 : xx
498 // ...
499 // }
500 if (ret !== undefined) {
501 module.exports = ret
502 }
503 }
执行a.js中的function方法,这时会调用var b = require("b.js"),
require方法会返回b的compile方法的返回值,b模块中又有var c = require('c.js')。
这时会调用c的compile方法,然后调用c的function,c中,如果要暴露对象,或者是return 对象c,则模块c的exports = c。或者直接是module.export = c;总之最后会返回module c.export = c;所以var c = module c.export = c,模块b中,就可以使用变量c调用模块c中的c对象的方法和属性。
以此类推,最终a模块也能调用b模块中b对象的属性和方法。
不管什么模块,只要使用了module.export = xx模块,其他模块就可以使用require("xx模块"),调用xx模块中的各种方法了。
最终模块的状态会变成module.status = STATUS.COMPILED。
Module.prototype._use = function(ids, callback) {
var uris = resolve(ids, this.uri); //解析['./a','jquery']
this._load(uris, function() { //把解析出来的a,jquery模块的地址[url1,url2],调用_load方法。
//util.map : 让数据成员全部执行一次一个指定的函数,并返回一个新的数组,该数组为原数组成员执行回调后的结果
var args = util.map(uris, function(uri) { return uri ? cachedModules[uri]._compile() : null;//如果存在url,就调用_compile方法。
})
if (callback) { callback.apply(null, args) }
})
}
这时args = [module a.export, module jquery.export];
seajs.use(['./a','jquery'],function(a,$){
var num = a.a;
$('#J_A').text(num);
})
这时function中的a和$就是module a.export和module jquery.export。
因为本人现在在研究jquery源码和jquery框架设计,因此共享一些经验:
jquery源码,我在网上看了很多解析,看着看着就看不下去了。意义不大,推荐妙味课堂的jquery源码解析。 司徒正美的javascript框架设计,个人觉得难度大,但是精读后,你就是高级前端工程师了。 玉伯的sea.js,我建议去学习,去用,毕竟是中国人自己做的。我们公司新的项目或者重构,都会使用seajs来做。 接下来就是模块化handbars以及mvc的backbone或者mvvm的angular的源码精读。这里我希望有人给我提建议,看什么书,看什么网站,看什么视频能够快速的学习。 加油!
第四课:seajs的模块编译_compile过程的更多相关文章
- Nginx网络架构实战学习笔记(四):nginx连接memcached、第三方模块编译及一致性哈希应用
文章目录 nginx连接memcached 第三方模块编译及一致性哈希应用 总结 nginx连接memcached 首先确保nginx能正常连接php location ~ \.php$ { root ...
- 简单实例讲解linux的module模块编译步骤
注:原博文地址http://blog.sina.com.cn/s/blog_4ba5b45e0102v25h.html ---------------------------------------- ...
- 【C语言探险】 第四课的第二部分:串
内容简单介绍 1.课程大纲 2.第二部分第四课: 字符串 3.第二部分第五课预告: 预处理 课程大纲 我们的课程分为四大部分,每个部分结束后都会有练习题,并会发布答案.还会带大家用C语言编写三个游戏. ...
- 【C语言探索之旅】 第二部分第四课:字符串
内容简介 1.课程大纲 2.第二部分第四课: 字符串 3.第二部分第五课预告: 预处理 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写三个游戏. ...
- 斯坦福大学自然语言处理第四课“语言模型(Language Modeling)”
http://52opencourse.com/111/斯坦福大学自然语言处理第四课-语言模型(language-modeling) 一.课程介绍 斯坦福大学于2012年3月在Coursera启动了在 ...
- linux 模块编译步骤(原)
linux 模块编译步骤(原) 博主推荐:<Linux命令模板Licote(原)> 本文将直接了当的带你进入linux的模块编译.当然在介绍的过程当中,我也会添加一些必要的注释,以便初学者 ...
- Nginx 高级配置-第三方模块编译
Nginx 高级配置-第三方模块编译 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 第三模块是对nginx 的功能扩展,第三方模块需要在编译安装Nginx 的时候使用参数--add ...
- JavaScript框架设计(四) 字符串选择器(选择器模块结束)
JavaScript框架设计(四) 字符串选择器(选择器模块结束) 经过前面JavaScript框架设计(三) push兼容性和选择器上下文的铺垫,实现了在某一元素下寻找,现在终于进入了字符串选择器 ...
- 介绍一种基于gulp对seajs的模块做合并压缩的方式
之前的项目一直采用grunt来构建,然后用requirejs做模块化,requirejs官方有提供grunt的插件来做压缩合并.现在的项目切到了gulp,模块化用起了seajs,自然而然地也想到了模块 ...
随机推荐
- C#与MATLAB混合编程
C#和MatLab的混合编程,充分利用了winform的直观显示和matlab的强大计算能力.在此以一个小例子的形式给大家讲述一下二者混合编程的实现. 一.软件的配置说明 C#版本:VS2010 ma ...
- 给Azure 虚机的硬盘扩充容量[转]
接到用户的需求,需要给Azure 上虚机的硬盘扩充空间,网上找到下面的资源,做个备忘: https://github.com/azure-contrib/WindowsAzureDiskResizer
- 记一次ftp服务器搭建走过的坑
记一次ftp服务器搭建走过的坑 1.安装 ①下载 wget https://security.appspot.com/downloads/vsftpd-3.0.3.tar.gz #要FQ ②解压 ta ...
- Android之TelephonyManager类的方法详解
TelephonyManager类主要提供了一系列用于访问与手机通讯相关的状态和信息的get方法.其中包括手机SIM的状态和信息.电信网络的状态及手机用户的信息.在应用程序中可以使用这些get方法获取 ...
- Hive UDF 实验1
项目中使用的hive版本低于0.11,无法使用hive在0.11中新加的开窗分析函数. 在项目中需要使用到row_number()函数的地方,有人写了udf来实现这个功能. new java proj ...
- [转]Oracle如何实现创建数据库、备份数据库及数据导出导入的一条龙操作
本文转自:http://www.cnblogs.com/wuhuacong/archive/2012/03/09/2387680.html Oracle中对数据对象和数据的管理,无疑都是使用PL/SQ ...
- uva 297 quadtrees——yhx
Quadtrees A quadtree is a representation format used to encode images. The fundamental idea behind ...
- POJ 1061 青蛙的约会【扩展欧几里德】
设跳的次数为t 根据题意可得以下公式:(x+mt)%L=(y+nt)%L 变形得 (x+mt)-(y+nt)=kL (n-m)t+kL=x-y 令a=(n-m),b=L,c=x-y 得 at+bk=c ...
- 我发现:在StackOverflow上拯救歪果仁十分有意思!
菊长:火星特工们!今天是周五了,大家有什么提议? BeJavaGod:报告菊长!我发现,在StackOverflow上拯救歪果仁十分有意思! 噗哈哈,时不时遇到问题会使用到StackOverflow, ...
- java 12-5 StringBuffer的几个案例
1. 把数组拼接成一个字符串 public class StringBufferTest2 { public static void main(String[] args) { //定义一个数组 in ...