博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第四课:seajs的模块编译_compile过程
阅读量:5735 次
发布时间:2019-06-18

本文共 4738 字,大约阅读时间需要 15 分钟。

最近比较闲,我就讲下seajs的模块编译_compile过程。

 这里紧接着第三课的例子来讲解。首先是a.js的编译

Module.prototype._compile = function() {126     var module = this          127     // 如果该模块已经编译过,则直接返回module.exports128     if (module.status === STATUS.COMPILED) {129       return module.exports130     }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     // 这里是处理一些异常情况,此时直接返回null137     if (module.status < STATUS.SAVED && !hasModifiers(module)) {138       return null139     }140     // 更改模块状态为COMPILING,表示模块正在编译141     module.status = STATUS.COMPILING142 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不正确,那么直接返回null152         if (!child) {153           return null154         }155 156         // Avoids circular calls.157         // 如果子模块的状态为STATUS.COMPILING,直接返回child.exports,避免因为循环依赖反复编译模块158         if (child.status === STATUS.COMPILING) {159           return child.exports160         }161         // 指向初始化时调用当前模块的模块。根据该属性,可以得到模块初始化时的Call Stack.162         child.parent = module163         // 返回编译过的child的module.exports164         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 = cachedModules177 178     // require是一个方法,用来获取其他模块提供的接口。179     module.require = require180     // exports是一个对象,用来向外提供模块接口。181     module.exports = {}182     var factory = module.factory183 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 = factory195 }196 197 // 更改模块状态为COMPILED,表示模块已编译198 module.status = STATUS.COMPILED199 // 执行模块接口修改,通过seajs.modify()200 execModifiers(module)201 return module.exports202 }
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 : xx497     //   ,fn2 : xx498     //   ...499     // }500     if (ret !== undefined) {501       module.exports = ret502     }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的源码精读。这里我希望有人给我提建议,看什么书,看什么网站,看什么视频能够快速的学习。 加油!
 
 
 
 
 
 

转载于:https://www.cnblogs.com/chaojidan/p/4126647.html

你可能感兴趣的文章
vim编辑器如何添加或删除多行注释
查看>>
[LeetCode] Merge Intervals
查看>>
iOS开发-按钮的基本使用
查看>>
在QT和SDL搭建的框架中使用OPENGL在SDL窗口上进行绘图
查看>>
REST技术第三步 @BeanParam的使用
查看>>
SharePoint 读取 Site Columns 的数据并绑定到DropdownList
查看>>
Python中的对象行为与特殊方法(二)类型检查与抽象基类
查看>>
使用 axios 详解
查看>>
通信基站(dfs回溯,思维)
查看>>
nginx web加密访问
查看>>
iOS - Regex 正则表达式
查看>>
第 68 章 Logical Volume Manager (LVM)
查看>>
膝盖中了一箭之康复篇-第八个月暨2月份目标总结
查看>>
IPA提交APPStore问题记录(一)
查看>>
有利于seo优化的网站地图不能取巧
查看>>
快照产品体验优化
查看>>
ASCII
查看>>
ibatis SqlMap not found
查看>>
Android SD卡创建文件和文件夹失败
查看>>
Ubuntu 14.04 vsftp refusing to run with writable root inside chroot问题解决方法
查看>>