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 }

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

  • 相关阅读:
    Jmeter之http性能测试实战 非GUI模式压测 NON-GUI模式 结果解析TPS——干货(十一)
    UI Recorder 自动化测试 回归原理(九)
    UI Recorder 自动化测试 录制原理(八)
    UI Recorder 自动化测试 整体架构(七)
    UI Recorder 自动化测试 配置项(六)
    UI Recorder 自动化测试 工具栏使用(五)
    UI Recorder 自动化测试 回归测试(四)
    UI Recorder 自动化测试 录制(三)
    UI Recorder 自动化测试工具安装问题疑难杂症解决(二)
    UI Recorder 自动化测试安装教程(一)
  • 原文地址:https://www.cnblogs.com/diligentYe/p/6439872.html
Copyright © 2011-2022 走看看