文章目录

浅谈requireJS源码 版本 2.3.3
开始是这样的
作者定义一个立即执行函数 有两个参数 global 和 setTimeOut
匿名函数开始是作者自己结合原生js定义的一些方法
例如:

function isFunction(it) {
return ostring.call(it) === ‘[object Function]’;
}
ostring是什么? 原来是 Object.prototype.toString

大致流程是
newContext函数开始
设置handlers对象
设置Module类
设置context对象
newContext函数完 返回值context对象
设置req函数
执行req({})
设置define函数
最后再次执行req({cfg})函数

-> newContext 中的部分代码 代码太多 不罗列
开始定义一堆属性 然后定义一下内部要用到的函数 设置handlers对象

有三个属性值 require  exports  module  

-> 设置Module类 模块类

-> 设置context对象

关键函数  configure 主要设置cfg的属性   makeShimExports函数  对shime进行特殊处理(即加载特殊要提前依赖的模块)
makerequir函数 定义加载的依赖模块函数   
其中调用mix混合对象属性  
nameToUrl函数 将模块名转换为路径 
load函数  调用req的load
 completeLoad函数 完成加载函数  
onScriptLoad函数  检查加载状态 如果加载完成 
interactiveScript的值置为null   继续调用completeLoad函数  completeLoad继续调用takeGlobalQueue 
onScriptError 检查script标签错误
好像    少了点什么  诶   checkLoaded  检查加载的 
在completeLoad函数中的最后调用checkLoaded
看一下核心函数 
 completeLoad: function (moduleName) {  //接受参数模块名称
        var found, args, mod,
            shim = getOwn(config.shim, moduleName) || {},
            shExports = shim.exports;
        takeGlobalQueue();    //推入队列
        while (defQueue.length) {
            args = defQueue.shift();
            if (args[0] === null) {
                args[0] = moduleName;
                if (found) {
                    break;
                }
                found = true;
            } else if (args[0] === moduleName) {
                found = true;
            }

            callGetModule(args);
        }
        context.defQueueMap = {};
        mod = getOwn(registry, moduleName);

        if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) {
            if (config.enforceDefine && (!shExports || !getGlobal(shExports))) {
                if (hasPathFallback(moduleName)) {
                    return;
                } else {
                    return onError(makeError('nodefine',
                                     'No define call for ' + moduleName,
                                     null,
                                     [moduleName]));
                }
            } else {
                callGetModule([moduleName, (shim.deps || []), shim.exportsFn]);
            }
        }

        checkLoaded();
    }

-> 核心函数req 接受四个参数 模块名数组 执行函数 错误处理 选项

 req = requirejs = function(deps,callback,errback,optional){...}
 if (!isArray(deps) && typeof deps !== 'string') {  //如果第一个参数不是数组 是一个定义对象 
      config = deps;       
      if (isArray(callback)) {
          deps = callback;
          callback = errback;
          errback = optional;
      } else {
          deps = [];
      }
  }
  if (config && config.context) {    
      contextName = config.context;
  }
  context = getOwn(contexts, contextName);
  if (!context) {
      context = contexts[contextName] = req.s.newContext(contextName);
  }
  if (config) {
      context.configure(config);
  }
  return context.require(deps, callback, errback);  //调用context的require  间接调用context 的makeRequire  返回闭包函数 localRequire 然后调用  zzzzzzzzz  执行 intakeDefines()函数  intakeDefines执行 takeGlobalQueue 将globalDefQueue push进context的队列 然后置为空数组
          /* 检测 入口 data-main */  
if (isBrowser && !cfg.skipDataMain) {  //判断是否是浏览器环境          isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document),
  eachReverse(scripts(), function (script) {
      if (!head) {
          head = script.parentNode;
      } dataMain = script.getAttribute('data-main');
      if (dataMain) {
      if (!cfg.baseUrl && mainScript.indexOf('!') === -1) {
              src = mainScript.split('/');
              mainScript = src.pop();
              subPath = src.length ? src.join('/')  + '/' : './';
              cfg.baseUrl = subPath;
          }
          mainScript = mainScript.replace(jsSuffixRegExp, '');
          if (req.jsExtRegExp.test(mainScript)) {
              mainScript = dataMain;
          }    
          cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript];   //将data-main的属性值推入dep中
          return true;
      }
  });

define函数

requireJS作者是这样定义的

define = function(name,deps,callback){…}
查阅官方api define有三种写法
第一种 包含三个参数 第一个参数是 模块的名称 第二个是引入的模块
第三个是 执行的函数
第二种 包含两个参数 第一个参数 是要引入的模块 第二个是要执行的函数
第三种 包含一个参数 就是执行的函数
源码是这样写的 外加我的注释

  /*  参数逻辑判断  */
if (typeof name !== 'string') {   //判断第一个参数是否是字符串 如果不是
        callback = deps;   //后面的参数向前移一位
        deps = name;
        name = null;
    }
    if (!isArray(deps)) {    //deps要引入模块是否是数组  如果不是  
        callback = deps;      //后面的参数前移
        deps = null;
    }
    /*如果传入参数中没有数组*/
    if (!deps && isFunction(callback)) {   
        deps = [];
        if (callback.length) {  //  判断callback实际接收的参数
            callback
                .toString()  // 将可执行函数转换为字符串
                .replace(commentRegExp, commentReplace) /* 这里是个正则匹配 commentRegExp = /\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/mg 用来过滤注释用的*/
                .replace(cjsRequireRegExp, function (match, dep) {
                    deps.push(dep);  //将require字段引入的push到dep中   
                });
            deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps);
        }
    }
 if (useInteractive) { //useInteractive在文初被设为false  这个应该是判断是IE(6-8)script标签做的特殊处理  (getInteractiveScript函数)ie6-8不支持script标签 支持onreadystatechange属性 有“uninitialized” – 原始状态 “loading” – 下载数据中..“loaded” – 下载完成 “interactive” – 还未执行完毕. “complete” – 脚本执行完毕.
        node = currentlyAddingScript || getInteractiveScript();
        if (node) {
            if (!name) {
                name = node.getAttribute('data-requiremodule'); //获得引入模块的名字
            }
            context = contexts[node.getAttribute('data-requirecontext')]; //找出模块中的名字
        }
    }  
         if (context) {             //将此模块加入队列中 
        context.defQueue.push([name, deps, callback]);    
        context.defQueueMap[name] = true;
    } else {
        globalDefQueue.push([name, deps, callback]);
    }

看一下执行代码

req.exec = function (text) {     /*将string文本eval  zzzzzzzzzzz*/
    return eval(text);
};

触发是 req.load这个函数开始执行 第二个参数是主要参数 即moduleName context.completeLoad(moduleName)
模块加载完成执行 onScriptLoad 然后 再次执行completeLoad然后一层层加载 -end

–转载声明出处

文章目录