首页 > 代码库 > require.js 源码解读——配置默认上下文

require.js 源码解读——配置默认上下文

  首先,我们先来简单说一下,require.js的原理:

    1、载入模块?

    2、通过模块名解析出模块信息,以及计算出URL?

    3、通过创建SCRIPT的形式把模块加载到页面中。?

    4、判断被加载的脚本,如果发现它有依赖就去加载依赖模块。如果不依赖其它模块,就直接执行factory方法

    ?5、等所有脚本都被加载完毕就执行加载完成之后的回调函数。

  从今天起,我们跟着我们简单的例子,通过跟踪代码,来了解require.js的源码。

 1 <!DOCTYPE html> 2 <html lang="en"> 3  4 <head> 5     <meta charset="UTF-8"> 6     <title>Document</title> 7     <!-- 引入require.js --> 8     <script data-main="./test.js" src="./require.js"></script> 9     </script>10     <script>11     require([a, b], function(a, b) {12         a.printA();13         b.printB();14     });15     </script>16 </head>17 18 <body>19 </body>20 21 </html>

 

  执行网页时,如果需要使用require.js作为模块加载器时,我们首先需要引入require.js。

1 <!-- 引入require.js -->2 <script data-main="./test.js" src="./require.js"></script>
 1 // a.js 2 define(function() { 3     return { 4         printA: console.log("I am A") 5     } 6 }); 7  8 // b.js 9 define(function() {10     return {11         printB: console.log("I am B")12     }13 });

 

  打开require.js文件我们可以发现,文件中首先定义了三个全局变量,之后便是一个自执行函数。因此在加载require.js文件时,自动执行自执行函数中的内容。

1 var requirejs, require, define;2 (function(global, setTimeout) {3     // 此处省略...4 }(this, (typeof setTimeout === ‘undefined‘ ? undefined : setTimeout)));

  首先我们,可以将require.js分为三个部分,

    1)定义全局变量和帮助函数

    2)模块加载核心部分

    3)定义require和define两个方法,以及项目入口。

技术分享

技术分享

技术分享

  如果我们使用跟踪代码的话,会发现文件一直都在定义变量和方法,一直执行到req({});这个语句调用req方法,传入一个空对象作为参数,用于创建一个默认上下文。现在我们跟踪代码,简单了解如何创建一个默认上下文。执行下面这段代码

 1 req = requirejs = function(deps, callback, errback, optional) { 2     // 此时传入的参数时空对象 3  4     //Find the right context, use default 5     var context, config, 6         contextName = defContextName; // 默认上下文名为_ 7  8     // Determine if have config object in the call. 9     // 此时传入一个空对象作为配置对象10     if (!isArray(deps) && typeof deps !== ‘string‘) {11         // deps is a config object12         config = deps;13         if (isArray(callback)) {14             // Adjust args if there are dependencies15             deps = callback;16             callback = errback;17             errback = optional;18         } else {19             deps = [];20         }21     }22     // config为空对象,没有设置context属性,因此不设置上下文名23     if (config && config.context) {24         contextName = config.context;25     }26 27     // getOwn函数:帮助函数,用于获取对象中对应属性的值,此时返回值为undefined28     context = getOwn(contexts, contextName);29     if (!context) {30         /*31             s = req.s = {32                 contexts: contexts,33                 newContext: newContext34             };35         */36         // 初始化时,执行下面这段代码,调用req.s中的newContext方法创建默认上下文37         // newContext方法时require.js的核心,此时我们只需要了解,它创建了一个默认上下文38         // 并且这个函数,只执行一次,之后的上下文,都是通过闭包,在闭包中,修改默认上下文的信息39         // 保存自己的上下文信息40         context = contexts[contextName] = req.s.newContext(contextName);41     }42 43     // 此时config为空对象,执行configure方法几乎没什么作用44     if (config) {45         context.configure(config);46     }47 48     // 跟踪代码可以发现调用context.require=>context.makeRequire()=>localRequire49     // context.require = context.makeRequire();50     // function localRequire(deps, callback, errback)51     // 返回一个localRequire52     return context.require(deps, callback, errback);53 };

  到这里,以及完成了context初始化。

  然后继续执行require({});下面的语句

 1 // 重置列出的函数 2 //Exports some context-sensitive methods on global require. 3 each([ 4     ‘toUrl‘, 5     ‘undef‘, 6     ‘defined‘, 7     ‘specified‘ 8 ], function(prop) { 9     //Reference from contexts instead of early binding to default context,10     //so that during builds, the latest instance of the default context11     //with its config gets used.12     req[prop] = function() {13         var ctx = contexts[defContextName];14         return ctx.require[prop].apply(ctx, arguments);15     };16 });17 18 // 获取添加脚本的父亲节点19 if (isBrowser) {20     head = s.head = document.getElementsByTagName(‘head‘)[0];21     //If BASE tag is in play, using appendChild is a problem for IE6.22     //When that browser dies, this can be removed. Details in this jQuery bug:23     //http://dev.jquery.com/ticket/270924     baseElement = document.getElementsByTagName(‘base‘)[0];25     if (baseElement) {26         head = s.head = baseElement.parentNode;27     }28 }

  以上仅仅是创建了默认上下文,并进行简单的处理。

require.js 源码解读——配置默认上下文