zoukankan      html  css  js  c++  java
  • 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 object
    12         config = deps;
    13         if (isArray(callback)) {
    14             // Adjust args if there are dependencies
    15             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函数:帮助函数,用于获取对象中对应属性的值,此时返回值为undefined
    28     context = getOwn(contexts, contextName);
    29     if (!context) {
    30         /*
    31             s = req.s = {
    32                 contexts: contexts,
    33                 newContext: newContext
    34             };
    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()=>localRequire
    49     // context.require = context.makeRequire();
    50     // function localRequire(deps, callback, errback)
    51     // 返回一个localRequire
    52     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 context
    11     //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/2709
    24     baseElement = document.getElementsByTagName('base')[0];
    25     if (baseElement) {
    26         head = s.head = baseElement.parentNode;
    27     }
    28 }

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

  • 相关阅读:
    12.16省选模拟t2 消防
    12.17省选模拟t3 围豆豆
    12.17省选模拟t1 生日礼物
    CF1322D Reality Show
    winform拖动无边框窗体
    关于ToolTip控件在XP系统中问题
    JDK源代码里面的一个for循环
    IIS5.1 无法运行asp.net网站但可访问静态页的解决方案
    winform窗体去掉标题头部的两种方式
    C# 语法之泛型
  • 原文地址:https://www.cnblogs.com/diligentYe/p/6439872.html
Copyright © 2011-2022 走看看