requirejs使用与原

RequireJS是一个非常小巧的JavaScript模块载入框架,是AMD规范最好的实现者之一
AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
基本形式:
require([module], callback);
下面介绍一下require的简单应用以及原理
更多的api可以查看官方网站http://requirejs.org/docs/api.html

资源地址:https://github.com/requirejs/requirejs

模块引用

//引入require.js,daya-main表示加载完requirejs后立即加载的js,一般是主模块
<script data-main="js/app.js" src="js/require.js"></script>

//配置路径
requirejs.config({
    //By default load any module IDs from js/lib
    baseUrl: 'js/lib',
    //except, if the module ID starts with "app",
    //load it from the js/app directory. paths
    //config is relative to the baseUrl, and
    //never includes a ".js" extension since
    //the paths config could be for a directory.
    paths: {
        app: '../app'
    }
});


//加载资源,执行回调
// Start the main app logic.
requirejs(['jquery', 'canvas', 'app/sub'],
function   ($,        canvas,   sub) {
    //jQuery, canvas and the app/sub module are all
    //loaded and can be used here now.
});
模块定义

//Definition Functions
//my/shirt.js now does setup work
//before returning its module definition.
define(function () {
    //Do setup work here

    return {
        color: "black",
        size: "unisize"
    }
});
//Definition Functions with Dependencies
//my/shirt.js now has some dependencies, a cart and inventory
//module in the same directory as shirt.js
define(["./cart", "./inventory"], function(cart, inventory) {
        //return an object to define the "my/shirt" module.
        return {
            color: "blue",
            size: "large",
            addToCart: function() {
                inventory.decrement(this);
                cart.add(this);
            }
        }
    }
);

代码结构

  • my/cart.js
  • my/inventory.js
  • my/shirt.js
加载非AMD模块方式
(1)exports值(输出的变量名),表明这个模块外部调用时的名称;(2)deps数组,表明该模块的依赖性。
require.config({
    shim: {

      'underscore':{
        exports: '_'
      },
      'backbone': {
        deps: ['underscore', 'jquery'],
        exports: 'Backbone'
      }
    }
  });


原理

这里简单解析一下requirejs工作原理

我们下个断点看看requirejs执行前后的head头


执行后

由此我们可以看出 requirejs模块加载的是依赖head.appendChild(script)

首先是函数的主入口

requirejs = function (deps, callback, errback, optional)
requirejs首先会获取依赖的deps,在一个全局变量registry中获取
function getModule(depMap) {
            var id = depMap.id,
                mod = getOwn(registry, id);

            if (!mod) {
                mod = registry[id] = new context.Module(depMap);
            }

            return mod;
        }
没有对应的模块则会根据模块名称加载一个新的module
req.load = function (context, moduleName, url)
创建过程 首先创建一个script
req.createNode = function (config, moduleName, url) {
        var node = config.xhtml ?
                document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
                document.createElement('script');
        node.type = config.scriptType || 'text/javascript';
        node.charset = 'utf-8';
        node.async = true;
        return node;
    };
然后设置监听事件 load
   node.setAttribute('data-requirecontext', context.contextName);
            node.setAttribute('data-requiremodule', moduleName);
  node.addEventListener('load', context.onScriptLoad, false);
            node.addEventListener('error', context.onScriptError, false);
讲load添加到head
head.appendChild(node);
下面是onScriptLoad监听事件和getScriptData函数
onScriptLoad: function (evt) {
                //Using currentTarget instead of target for Firefox 2.0's sake. Not
                //all old browsers will be supported, but this one was easy enough
                //to support and still makes sense.
                if (evt.type === 'load' ||
                        (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) {
                    //Reset interactive script so a script node is not held onto for
                    //to long.
                    interactiveScript = null;

                    //Pull out the name of the module and the context.
                    var data = getScriptData(evt);
                    context.completeLoad(data.id);
                }
            }


 function getScriptData(evt) {
            //Using currentTarget instead of target for Firefox 2.0's sake. Not
            //all old browsers will be supported, but this one was easy enough
            //to support and still makes sense.
            var node = evt.currentTarget || evt.srcElement;

            //Remove the listeners once here.
            removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange');
            removeListener(node, context.onScriptError, 'error');

            return {
                node: node,
                id: node && node.getAttribute('data-requiremodule')
            };
        }
laod完成后获取script资源创建module并注入registry。

关于module结构
Module = function (map) {
            this.events = getOwn(undefEvents, map.id) || {};
            this.map = map;
            this.shim = getOwn(config.shim, map.id);
            this.depExports = [];
            this.depMaps = [];
            this.depMatched = [];
            this.pluginMaps = {};
            this.depCount = 0;

            /* this.exports this.factory
               this.depMaps = [],
               this.enabled, this.fetched
            */
        };
这是加载单个dependency的过程,requirejs加载dependency的时候是
require([module], callback);
那么是如何保证多个module加载完成后才去执行callback?
我们可以看到函数localRequire,返回return localRequire 连续调用
  function localRequire(deps, callback, errback)
//code
 //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();
                    });
//code
return localRequire;
}
checkLoaded会检测模块有没有加载完成,用定时器去检测状态。
if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
                    checkLoadedTimeoutId = setTimeout(function () {
                        checkLoadedTimeoutId = 0;
                        checkLoaded();
                    }, 50);
                }
总结:requirejs是非常轻量级的js库,压缩之后的仅14kb;requirejs按需加载js,无需像以前一样大量引入js文件;requirejs遵循AMD规则,异步加载js;requirejs支持模块化编程,强调模块的独立性与模块之间依赖性。


















评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值