RequireJS源码解读(二)
2017-03-24 17:02
351 查看
(续上节)
上面讲了如何处理全局序列和context化全局序列
以及执行全局序列中的依赖项。
检查依赖项
最后返回的是 return localRequire;
回到 context.require(deps, callback, errback);
脚本加载的回调,用于检查加载状态。
var data = getScriptData(evt) 这个函数 构造完毕之后,将返回一个对象
![](http://img.blog.csdn.net/20170324153523834?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
此时data就是{ node:script对象,id : ‘main’ }
![](http://img.blog.csdn.net/20170324153815590?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
运行到这里,callGetModule()就是调用module了吧
![](http://img.blog.csdn.net/20170324154202071?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
传入的args :args = [“main”, Array[0], undefined]
args[1]和args[2]到底是来干嘛的?
从下图可以看到args[1]是当前加载项的父节点, args[2]->applyMap?:
![](http://img.blog.csdn.net/20170324154624761?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
转化为绝对路径
最后将main.js转化为url路径,可能在这里没什么用,但是在这种定义了baseURL或者重命名模块中,这个normolize显得非常有用的
![](http://img.blog.csdn.net/20170324155223545?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
最后得到的对象:
![](http://img.blog.csdn.net/20170324155310451?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20170324155512380?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20170324155745032?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20170324161855209?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
然而不是a.js,第二次遍历加载出了a.js
![](http://img.blog.csdn.net/20170324162151841?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
又见到熟悉的@r5.js,这次它变成了Module
![](http://img.blog.csdn.net/20170324162335090?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
传入的参数:
这个path是在main.js中定义的
deps=[‘main’],应该main默认就为依赖项吧,因为之前在
![](http://img.blog.csdn.net/20170324163019725?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
createNode()就是构造一段script,而且指定了charset-set 和async(异步加载);
![](http://img.blog.csdn.net/20170324163811677?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
这两句话为node添加了新的属性
![](http://img.blog.csdn.net/20170324164148318?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
为node绑定新的事件
加载事件和error事件都绑定为context的对象了
其实node就是script,但是require这里为它添加了两个新的属性和新的load处理事件,我觉得requireJS的精妙之处就在这里吧。
继续循环看是否有加载项
这个时候a.js并没有加载,又出现了.@r5,我猜测b.js要出来了
![](http://img.blog.csdn.net/20170324164705605?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
然而我们看到的是,removeScript(“a”),要移除a了?但是a都没有加载啊
![](http://img.blog.csdn.net/20170324164843573?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
不对,这里是要加载a.js,然而报错了,应该是因为我们debug超出了requireJS的时间。
![](http://img.blog.csdn.net/20170324165043902?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMjUxMjcwNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
.@r6 .@r8出现了
先写到这里,requireJS的原理确切是很复杂,经常会对一些全局变量进行修改啥的。
到这里onScriptLoad()就结束了
上面讲了如何处理全局序列和context化全局序列
以及执行全局序列中的依赖项。
检查依赖项
//Mark all the dependencies as needing to be loaded. context.nextTick(function() { //Some defines could have been added since the //require call, collect them. intakeDefines(); requireMod = getModule(makeModuleMap(null, relMap)); //Store if map config should be applied to this require //call for dependencies. requireMod.skipMap = options.skipMap; requireMod.init(deps, callback, errback, { enabled: true }); checkLoaded(); });
最后返回的是 return localRequire;
回到 context.require(deps, callback, errback);
4. 监听页面加载
传入的参数是load加载事件脚本加载的回调,用于检查加载状态。
onScriptLoad: function(evt) { //Using currentTarget instead of target for Firefox 2.0's sake. Not //all old browsers will be supported, but this one was easy enough //to support and still makes sense. if (evt.type === 'load' || (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) { //Reset interactive script so a script node is not held onto for //to long. interactiveScript = null; //Pull out the name of the module and the context. var data = getScriptData(evt); context.completeLoad(data.id); }
var data = getScriptData(evt) 这个函数 构造完毕之后,将返回一个对象
此时data就是{ node:script对象,id : ‘main’ }
5.获取加载对象
开始加载completeLoad: function(moduleName) { var found, args, mod, shim = getOwn(config.shim, moduleName) || {}, shExports = shim.exports; takeGlobalQueue(); while (defQueue.length) { args = defQueue.shift(); if (args[0] === null) { args[0] = moduleName; //If already found an anonymous module and bound it //to this name, then this is some other anon module //waiting for its completeLoad to fire. if (found) { break; } found = true; } else if (args[0] === moduleName) { //Found matching define call for this script! found = true; } callGetModule(args); } context.defQueueMap = {}; //Do this after the cycle of callGetModule in case the result //of those calls/init calls changes the registry. mod = getOwn(registry, moduleName);
运行到这里,callGetModule()就是调用module了吧
function callGetModule(args) { //Skip modules already defined. if (!hasProp(defined, args[0])) { getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]); } }
传入的args :args = [“main”, Array[0], undefined]
args[1]和args[2]到底是来干嘛的?
5.1 创造ModuleMap对象
首先makeModuleMap(args[0], null, true)).init(args[1], args[2]从下图可以看到args[1]是当前加载项的父节点, args[2]->applyMap?:
转化为绝对路径
最后将main.js转化为url路径,可能在这里没什么用,但是在这种定义了baseURL或者重命名模块中,这个normolize显得非常有用的
最后得到的对象:
5.2 getModule
5.3 Module.init
5.4 checkLoaded()
checkLoaded()会调用onScriptLoad(),出现了新的./@r5.js 是a.js吗然而不是a.js,第二次遍历加载出了a.js
又见到熟悉的@r5.js,这次它变成了Module
6 加载第一个script:a.js
req.load = function(context, moduleName, url) { var config = (context && context.config) || {}, node; if (isBrowser) { //In the browser so use a script tag node = req.createNode(config, moduleName, url); node.setAttribute('data-requirecontext', context.contextName); node.setAttribute('data-requiremodule', moduleName);
6.1 检测是否是浏览器
isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document),
6.2 创建node
req.createNode = function(config, moduleName, url) { var node = config.xhtml ? document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : document.createElement('script'); node.type = config.scriptType || 'text/javascript'; node.charset = 'utf-8'; node.async = true; return node; };
传入的参数:
这个path是在main.js中定义的
require.config({ path: { "a": "a", "b": "b" } })
deps=[‘main’],应该main默认就为依赖项吧,因为之前在
createNode()就是构造一段script,而且指定了charset-set 和async(异步加载);
node.setAttribute('data-requirecontext', context.contextName); node.setAttribute('data-requiremodule', moduleName);
这两句话为node添加了新的属性
为node绑定新的事件
node.addEventListener('load', context.onScriptLoad, false); node.addEventListener('error', context.onScriptError, false);
加载事件和error事件都绑定为context的对象了
其实node就是script,但是require这里为它添加了两个新的属性和新的load处理事件,我觉得requireJS的精妙之处就在这里吧。
继续循环看是否有加载项
这个时候a.js并没有加载,又出现了.@r5,我猜测b.js要出来了
然而我们看到的是,removeScript(“a”),要移除a了?但是a都没有加载啊
不对,这里是要加载a.js,然而报错了,应该是因为我们debug超出了requireJS的时间。
.@r6 .@r8出现了
先写到这里,requireJS的原理确切是很复杂,经常会对一些全局变量进行修改啥的。
到这里onScriptLoad()就结束了
相关文章推荐
- RequireJs 源码解读
- RequireJs 源码解读及思考
- spring beans源码解读之--XmlBeanFactory
- mvc源码解读(2)-mvc路由注册
- sinatra源码解读
- Netty源码解读(四)Netty与Reactor模式
- LruCache源码解读
- Spark学习笔记(11)源码解读之Driver中的ReceiverTracker架构
- Concurrent包源码解读之CountDownLatch,Semaphore,CyclicBarrier
- 16.Spark Streaming源码解读之数据清理机制解析
- mvc源码解读(5)-Controller工厂的创建
- YYModel 源码解读(二)之NSObject+YYModel.h (5)
- CYYMysql 源码解读 3
- redis源码解读----Redis启动都干了啥
- Gson 源码解读
- dubbo源码深度解读之rpc模块
- Apache OFbiz service engine 源码解读
- SpringMVC源码解读 - RequestMapping注解实现解读 - RequestCondition体系
- 源码解读android 5.0控件TabLayout无法自定义下划线宽度问题
- gnu coreutils4.5.1 uname.c源码解读