昨天大概了解了以下requirejs的主要入口req方法和上下文newContext方法,说实话到目前为止这些方法是做什么的,有什么用我们还是一无所知,接下来先看些esay一点的代码
在执行了一次空参数的req方法之后,代码跳到了这里
这个方法遍历了所有的script标签,获取到有data-main属性的值,也就是我们定义的入口文件(正常都是main.js)。如果mainScript路径中不带!(带!表示插件)而且没有定义baseUrl,则使用mainScript的路径为baseUrl,并且将mainScript作为依赖项加到cfg配置中
然后代码就执行到源码的倒数第二行了
Oh,no!刚执行了一次req方法现在又执行了一次,只不过第一次执行的时候参数是个空对象,这里却有了新的东西。一个是baseUrl,这是所有模块的相对路径,deps依赖项里面有一个main模块,也是我们定义在script标签中的“data-main=main.js”。接下来的事情我猜就是要去加载main.js并且执行它。那到底是不是这样呢?我们继续往下看
在上面的截图中可以看到第二次执行req方法是内部一些变量的新值。这是后context要根据新的config进行配置了,进入到context.configure方法中去
好吧由于cfg中参数只有两个,configure方法里面很多判断分支并没有执行进去,一直到这里
context.require方法,其实就是上一章中提到的localRequire方法,只不过这一次它是带着参数去执行的
这里会再去遍历全局队列globalDefQueue和context.defQueue。此时并没有define过模块,所以这两个队列里面依然是空的,啥都没做
这个时候又会创建一个异步的函数,不过这次在requireMod.init方法里面传入了依赖项main模块,这里具体做了什么我们待会再看,先看完req方法传入新的cfg最后的结果。
在req方法的最后又会执行一遍localRequire方法。。。又是一堆空的参数,啥事都没做。好了,我们终于可以深入探究一下nextTick回调里面究竟干了什么
首先,它先调用了熟悉的intakeDefines方法去取队列里面define的模块,这个时候队列依然是空的。接下来的方法先调用了makeModuleMap方法对module的一些信息进行了处理,我们直接看它的返回值
目前还没有看到什么有用的信息,因为传入的是一些空的参数,至于函数里面具体做了什么暂且先跳过。再看一下getModule方法
这个方法很简单,在全局的registry中搜索一次模块有没有被注册过,如果没有,就实例化一个新的Module对象并且注册。
可以看出Module对象里面主要是一些依赖项的信息和工具方法,等到具体使用的时候我们再去一一分析
接下来终于要初始化模块了!!
一路往下跳,由于传入参数enable=true,所以直接跳到这里
这里调用module的enable方法。这又是好长一段代码
我又是本着能跳过先跳过的原则,直接看事件绑定的这一块
这里对依赖项注册了一个事件,只要它被define了,就会去检查它的依赖项有没有下载并且执行生成export对象。这里的check方法我们很快就可以看到了
绑定完事件之后,就开始执行check方法
check方法主要是检测模块的依赖项有没有都执行完成,如果都执行完了,就执行自己的回调函数生成export对象,如果没有,就检查该模块有没有下载注册,没有的话就去下载执行,至于代码具体如何实现的,我们留着下次再看!
总结:
1、解析出页面script标签里的data-main,得到main模块和baseUrl
2、初始化一个模块的时候会先去加载它的依赖项,第一个依赖项就是main模块
3、初始化模块的时候会先调用enable方法注册依赖项的事件定义,在依赖项被define的时候接收回调。早enable方法的最后会执行check方法检测依赖项是否都已加载完成,如果没有就先去加载依赖项