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

    1、载入模块


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


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


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

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

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

 <!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<title>Document</title>
<!-- 引入require.js -->
<script data-main="./test.js" src="./require.js"></script>
</script>
<script>
require(['a', 'b'], function(a, b) {
a.printA();
b.printB();
});
</script>
</head> <body>
</body> </html>

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

 <!-- 引入require.js -->
<script data-main="./test.js" src="./require.js"></script>
 // a.js
define(function() {
return {
printA: console.log("I am A")
}
}); // b.js
define(function() {
return {
printB: console.log("I am B")
}
});

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

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

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

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

    2)模块加载核心部分

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

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

 req = requirejs = function(deps, callback, errback, optional) {
// 此时传入的参数时空对象 //Find the right context, use default
var context, config,
contextName = defContextName; // 默认上下文名为_ // Determine if have config object in the call.
// 此时传入一个空对象作为配置对象
if (!isArray(deps) && typeof deps !== 'string') {
// deps is a config object
config = deps;
if (isArray(callback)) {
// Adjust args if there are dependencies
deps = callback;
callback = errback;
errback = optional;
} else {
deps = [];
}
}
// config为空对象,没有设置context属性,因此不设置上下文名
if (config && config.context) {
contextName = config.context;
} // getOwn函数:帮助函数,用于获取对象中对应属性的值,此时返回值为undefined
context = getOwn(contexts, contextName);
if (!context) {
/*
s = req.s = {
contexts: contexts,
newContext: newContext
};
*/
// 初始化时,执行下面这段代码,调用req.s中的newContext方法创建默认上下文
// newContext方法时require.js的核心,此时我们只需要了解,它创建了一个默认上下文
// 并且这个函数,只执行一次,之后的上下文,都是通过闭包,在闭包中,修改默认上下文的信息
// 保存自己的上下文信息
context = contexts[contextName] = req.s.newContext(contextName);
} // 此时config为空对象,执行configure方法几乎没什么作用
if (config) {
context.configure(config);
} // 跟踪代码可以发现调用context.require=>context.makeRequire()=>localRequire
// context.require = context.makeRequire();
// function localRequire(deps, callback, errback)
// 返回一个localRequire
return context.require(deps, callback, errback);
};

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

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

 // 重置列出的函数
//Exports some context-sensitive methods on global require.
each([
'toUrl',
'undef',
'defined',
'specified'
], function(prop) {
//Reference from contexts instead of early binding to default context,
//so that during builds, the latest instance of the default context
//with its config gets used.
req[prop] = function() {
var ctx = contexts[defContextName];
return ctx.require[prop].apply(ctx, arguments);
};
}); // 获取添加脚本的父亲节点
if (isBrowser) {
head = s.head = document.getElementsByTagName('head')[0];
//If BASE tag is in play, using appendChild is a problem for IE6.
//When that browser dies, this can be removed. Details in this jQuery bug:
//http://dev.jquery.com/ticket/2709
baseElement = document.getElementsByTagName('base')[0];
if (baseElement) {
head = s.head = baseElement.parentNode;
}
}

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

require.js 源码解读——配置默认上下文的更多相关文章

  1. js便签笔记(10) - 分享:json2.js源码解读笔记

    1. 如何理解“json” 首先应该意识到,json是一种数据转换格式,既然是个“格式”,就是个抽象的东西.它不是js对象,也不是字符串,它只是一种格式,一种规定而已. 这个格式规定了如何将js对象转 ...

  2. js便签笔记(10) - 分享:json.js源码解读笔记

    1. 如何理解“json” 首先应该意识到,json是一种数据转换格式,既然是个“格式”,就是个抽象的东西.它不是js对象,也不是字符串,它只是一种格式,一种规定而已. 这个格式规定了如何将js对象转 ...

  3. fastclick.js源码解读分析

    阅读优秀的js插件和库源码,可以加深我们对web开发的理解和提高js能力,本人能力有限,只能粗略读懂一些小型插件,这里带来对fastclick源码的解读,望各位大神不吝指教~! fastclick诞生 ...

  4. require.js源码分析

    写的寥寥草草,博客园的布局怎么弄还没有研究,再保存一份草稿,日后在完善,深度研究 require.js 加载顺序 1:加载html主页,require.js文件 2:脚本执行到html中的script ...

  5. prototype.js 源码解读(02)

    如果你想研究一些比较大型的js框架的源码的话,本人建议你从其最初的版本开始研读,因为最初的版本东西少,易于研究,而后的版本基本都是在其基础上不断扩充罢了,所以,接下来我不准备完全解读prototype ...

  6. Mybatis源码解读-配置加载和Mapper的生成

    问题 Mybatis四大对象的创建顺序? Mybatis插件的执行顺序? 工程创建 环境:Mybatis(3.5.9) mybatis-demo,参考官方文档 简单示例 这里只放出main方法的示例, ...

  7. prototype.js 源码解读(01)

    prototype.js是一个设计的非常优雅且很有实用价值的js基础类库,其源码非常值得研究.研究它的源码不仅能提升个人水平,而且对你打下坚实的js基础也很有帮助.因本人技术水平有限,该解读仅供参考. ...

  8. Require.js 源码分析

    本文将简单介绍下个人对require.js的源码分析,简单分析实现原理 一.require加载资源的流程 require中,根据AMD(Asynchronous Module Definition)的 ...

  9. json2.js源码解读记录

    相关内容:json详细用法.js语法.unicode.正则   json特点--最简单.最小巧的经典js库.   json作者:道克拉斯.克劳福德(Douglas Crockford)--js大牛 出 ...

随机推荐

  1. Unity编程标准导引-2.2Unity中的基本概念

    2.2Unity中的基本概念 上述介绍提到了几个概念:游戏对象.场景.资源.相机,这个小节我们来深入了解,同时进行一些实践性操作.不过首先,我们需要大概了解一下Unity的工程文件夹. 2.2.1工程 ...

  2. [java多线程] - 锁机制&同步代码块&信号量

    在美眉图片下载demo中,我们可以看到多个线程在公用一些变量,这个时候难免会发生冲突.冲突并不可怕,可怕的是当多线程的情况下,你没法控制冲突.按照我的理解在java中实现同步的方式分为三种,分别是:同 ...

  3. 【转载】HTTP Cookie学习笔记

    什么是cookie? cookie是什么?是饼干,小甜点? No! No! No! 我今天要总结的cookie并不是你所想的小甜心,我这里要说的cookie是Web开发中的一个重要的"武器& ...

  4. C++_运算符重载

    什么是运算符的重载? 运算符与类结合,产生新的含义. 为什么要引入运算符重载? 作用:为了实现类的多态性(多态是指一个函数名有多种含义) 怎么实现运算符的重载? 方式:类的成员函数 或 友元函数(类外 ...

  5. 用Ajax实现自动刷新news功能

    这是Ajax应用的一个小实例:在页面中自动刷新功能,比如整个新闻页面中某一个小版块的内容,无需刷新整个页面就可以自动更新: 1.首先创建简单的页面元素: <body> <input ...

  6. NSIndexSet 浅析

    Cocoa 中提供了两个用于维护区间集合的类型:NSIndexSet和NSMutableIndexSet . 这两个类型容易其名字一样,其区别就在于是否可以修改.这个区别和NSArray的一样,NSI ...

  7. 2017-2-23 C#基础 中间变量

    用中间变量做这个题 1."请输入年份:"(1-9999) "请输入月份:"(1-12) "请输入日期:"(要判断大小月,判断闰年) 判断输入 ...

  8. 项目中通过Sorlj获取索引库中的数据

    在开发项目中通过使用Solr所提供的Solrj(java客户端)获取索引库中的数据,这才是真正对项目起实质性作用的功能,提升平台的检索性能及检索结果的精确性 第一步,引入相关依赖的jar包 第二步,根 ...

  9. 利用nginx concat模块合并js css

    前言: nginx-http-concat模块是由淘宝网开发的,现在淘宝网合并js和css正是用这个模块,如链接http://a.tbcdn.cn/??s/kissy/1.2.0/kissy-min. ...

  10. C# TCP多线程服务器示例

    前言 之前一直很少接触多线程这块.这次项目中刚好用到了网络编程TCP这块,做一个服务端,需要使用到多线程,所以记录下过程.希望可以帮到自己的同时能给别人带来一点点收获- 关于TCP的介绍就不多讲,神马 ...