ReqiureJS实现原理(一)
来源:互联网 发布:淘宝客服提成2个点 编辑:程序博客网 时间:2024/06/07 01:56
requireJS三个测试文件
main.js
require.config({ path: { "a": "a", "b": "b" }})require(['a'], function(a) { console.log('main');})
a.js
define(['b'], function(b) { console.log('a');})
执行结果
ba.js:2 amain.js:8 main
可以看到执行顺序 b,a.js main.js,即加载完b.js->a.js->main.js
源码阅读
构造上下文
打开调试窗口:
这段代码初始化了一个上下文对象context,调用的是req方法
req = requirejs = function(deps, callback, errback, optional) { //找到上下文信息,用default:defContextName 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 = []; } }
1.判断是否是数组
dep传入的参数是一个数组[‘a’],因为我们是require([‘a’])
require还可以加载很多模块,都是通过数组的参数传入。例如
require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){ // some code here });
定义了如果deps为非数组的处理方式
//requireJS判断数组的方式 var op = Object.prototype, ostring = op.toString;function isArray(it) { return ostring.call(it) === '[object Array]';}
当然,我们这里是array,这段函数就跳过去了,如果非数组就抛出异常了;
下一步
2.判断是否是数组
判断是否有config,没有配置参数,也跳过了
if (config && config.context) { contextName = config.context; }
config && config.context=undefined,因为我们没有指定参数
3.构造上下文
3.1检测上下文
context=getOwn(contexts,contextName)
81-87
var hasOwn = op.hasOwnProperty, //21 //判断obj是否有prop属性 function hasProp(obj, prop) { return hasOwn.call(obj, prop); } function getOwn(obj, prop) { return hasProp(obj, prop) && obj[prop]; }
这里的obj是Object,prop是”_“
hasProp(obj, prop)返回的是true
首先检测obj是否含有prop的属性,如果有的话,就返回obj[prop],没有就返回false ,返回的是一个obj._ 也就是Context对象
Module: function (map) {completeLoad: function (moduleName) {config: Objectconfigure: function (cfg) {contextName: "_"defQueue: Array[0]defined: Objectenable: function (depMap) {execCb: function (name, callback, args, exports) {load: function (id, url) {makeModuleMap: function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {makeRequire: function (relMap, options) {makeShimExports: function (value) {nameToUrl: function (moduleName, ext, skipExt) {nextTick: function (fn) {onError: function onError(err, errback) {onScriptError: function (evt) {onScriptLoad: function (evt) {registry: Objectrequire: function localRequire(deps, callback, errback) {urlFetched: Object__proto__: Object
这里context对象已经存在了,其实我都不知道什么时候存在的,难道是前几次加载的时候写进去的?(相当于缓存)
if (!context) { context = contexts[contextName] = req.s.newContext(contextName); }
3.2如果没有上下文,则构造
前面看到context的结构,那么context是如何构造的呢?
这里有一段代码,因为每次构造新的context的时候,都会保存进contexts,也就是说已经构建过的依赖将存在contexts中;
//Used to filter out dependencies that are already paths. req.jsExtRegExp = /^\/|:|\?|\.js$/; req.isBrowser = isBrowser; s = req.s = { contexts: contexts, newContext: newContext };
源码198-1751都在构造上下文,这里就先跳过。
我们只要知道context的内容就好了。
构造完毕后,第一步进入了context.makeRequire函数
1449-1668行 :localRequire()函数
//Grab defines waiting in the global queue. intakeDefines(); //Mark all the dependencies as needing to be loaded. context.nextTick(function() { //Some defines could have been added since the //require call, collect them. intakeDefines(); requireMod = getModule(makeModuleMap(null, relMap)); //Store if map config should be applied to this require //call for dependencies. requireMod.skipMap = options.skipMap; requireMod.init(deps, callback, errback, { enabled: true }); checkLoaded();
//将defines放在全局序列中 reqiure中的方法,不是context中的方法了
intakeDefines();
function intakeDefines() { var args; //Any defined modules in the global queue, intake them now. //如果全局队列有defined modules,现在就进入它们 takeGlobalQueue(); //Make sure any remaining defQueue items get properly processed. while (defQueue.length) { args = defQueue.shift(); if (args[0] === null) { return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1])); } else { //args are id, deps, factory. Should be normalized by the //define() function. callGetModule(args); } } context.defQueueMap = {}; }
takeGlobalQueue()是一个内部方法,将全局序列转化为context化的序列,具体如何实现的就不细说了,代码在558-570行。
只是这列有一个疑问,什么是全局序列,为什么会存在全局序列?
- ReqiureJS实现原理(一)
- ERPCore实现原理(一)
- JobTracker实现原理(一)
- HashMap实现原理(一)
- ProcessHacker实现原理(一)
- Sruts 笔记一(基本实现原理)
- 购物车实现原理(一)
- Android多线程一(AsyncTask实现原理)
- 数据库水平切分实现原理(一)
- HTTP 代理原理及实现(一)
- block 实现原理详解(一)
- HTTP 代理原理及实现(一)
- SSO认证服务器实现原理(一)
- 决策树算法原理与实现(一)
- GDB(一):gdb 实现原理
- HTTP 代理原理及实现(一)
- Android--推送机制实现原理(一)
- Redux原理(一):Store实现分析
- LeetCode:350. Intersection of Two Arrays II
- 银行卡卡号检测Luhn算法 Objective-C实现
- Android6.0(棉花糖)以上动态获取权限方法
- lianmai SDK流程图
- C# 模拟网站登陆
- ReqiureJS实现原理(一)
- Linux 中的标准输出
- python的request模块
- 文章标题
- 网站添加QQ登陆,QQ登录报错,是为什么呢
- Oracle数据库挂了后weblogic的日志
- MyEclipse 8.5反编译插件jad安装方法
- VS2005 MFC C/C++ 操作excel【网上找了好多列子,都不合适,自己总结一下】
- iOS与网页JS交互