• requireJS的使用


    转自:http://home.cnblogs.com/u/snandy/

    一、

    加载JavaScript文件:
    RequireJS的目标是鼓励代码的模块,它使用不同于传统<script>标签的脚本加载步骤。
    可以用它来加速、优化代码,但其主要目的还是为了代码的模块化,它鼓励在使用脚本时以
    module ID替代URL地址
    RequireJS以一个相对于baseUrl的地址来加载所有的代码,页面顶层<script>标签含有一个特殊
    的属性data-main,require.js使用他来启动脚本加载过程,而baseUrl一般设置到与该属性相一致
    的目录,下列示例中展示baseUrl的设置:
    <script data-main="scripts/main.js" src="scripts/require.js"></script>
    baseUrl亦可通过RequireJS config手动设置,如果没有显示指定config及data-main,则默认的baseUrl
    为包含RequireJS的那个HTML页面的所属目录。
    RequireJS默认所有的依赖资源都是js脚本,因此无需在module ID上再添加“.js”后缀
    RequireJS在进行moduleID到path的解析时会自动补上后缀,你可以通过paths config设置一组脚本,
    这是有助于我们在使用脚本时码更少的字
    有时候你想避开“baseUrl+paths”的解析过程,而是直接指定加载某一个目录下的脚本,此时可以这样做:
    如果一个module ID符合下述规则之一,其ID解析会避开常规的“baseUrl+paths”配置,而是直接将其加载为
    一个相对于当前HTML文档的脚本:
    ·以“.js”结束
    ·以“/”开始
    ·包含URL协议,如“http:”or“https:”
    一般来说,最好还是使用baseUrl及“paths” config去设置module ID。它会给你带来额外的灵活性,
    如便于脚本的重命名、重定位等。同时,为了避免凌乱的配置,最好不要使用多级嵌套的目录层次来
    组织代码,而是要么将所有的脚本都放置到baseUrl中,要么分置为项目库/第三方库的一个扁平结构,如下:

    注意在示例中,三方库jQuery没有将版本号包含在他们的文件夹中。我们建议将版本信息放置在单独的文件中来
    进行跟踪。使用诸如volo这类的工具,可以将package.json打上版本信息,并在磁盘上保持文件名为‘jquery.js’
    这有助于你保持配置的最小化,避免为每个库版本设置一条path,例如,将‘jquery’配置为“jquery-1.7.2”

    理想状况下,每个加载的脚本都是通过define()来定义的一个模块;但有些“浏览器全局变量注入”型的传统/遗留库
    并没有使用define()来定义它们的依赖关系,你必须为此使用shim config来指明它们的依赖关系,如果你没有
    指明依赖关系,加载可能报错,这是因为基于速度的原因,RequireJS会异步地以无序的形式加载这些库

    data-main入口点:
    require.js在加载的时候会检查data-main属性:
    <script data-main="scripts/main" src="scripts/require.js"></script>
    你可以在啊data-main指向的脚本中设置模块加载选项,然后加载第一个应用模块。注意:你在main.js中所设置
    的脚本是异步加载的,所以如果你在页面中配置了其他JS加载,则不能保证它们所依赖的JS已经加载成功

    例如:
    <script data-main="scripts/main" src="scripts/require.js"></script>
    <script src="scripts/other.js"></script>

    //contents of main.js:
    require.config({
    paths : {
    foo : 'libs/foo-1.1.3'
    }
    })

    //contents of other.js:
    //This code might be called before the require.config() in main.js
    //has executed When that happens, require.js will attempt to
    //load 'scripts/foo.js' instead of 'scripts/libs/foo-1.1.3.js'
    require(['foo'],function(foo){

    });

    定义模块:
    模块不同于传统的脚本文件,他良好的定义了一个作用域来避免全局名称空间污染,它可以显式
    地列出其依赖关系,并以函数(定义此模块的那个函数)参数的形式将这些依赖进行注入,而无需
    引用全局变量,Require.js的模块是模块模式的一个扩展,其好处是无需全局地引用其他模块

    require.js的模块语法允许它尽快地加载多个模块,虽然加载的顺序不订,但依赖的顺序最终
    是正确的,同时因为无需创建全局变量,甚至可以做到在同一个页面上同时加载同一模块的不同版本

    一个磁盘文件应该只定义1个模块,多个模块可以使用内置优化工具将其组织打包。
    1、简单的值对:
    如果一个模块仅含值对,没有任何依赖,则在define()中定义这些值对就好了:
    define({
    color:'black',
    size:'unisize'
    })
    2、函数式定义:
    如果一个模块没有任何依赖,但需要一个做setup工作的函数,则在define()中定义该函数
    ,并将其传给define()
    define(function(){
    return {
    color:'black',
    size:'unisize'
    }
    });
    3、存在依赖的函数式定义:
    如果模块存在依赖:则第一个参数是依赖的名称数组;第二个参数是函数,在模块的所有依赖加载
    完毕后,该函数会被调用来定义该模块,因此该模块应该返回一个定义本模块的object,依赖关系
    会以参数的形式注入到该函数上,参数列表与依赖名称列表一一对应。
    define(['./cart','./inventory'],function(cart,inventory){
    return {
    color:'blue',
    size:'large',
    addTocart:function(){
    inventory.decrement(this);
    cart.add(this);
    }
    }
    })
    本示例创建了一个my/shirt模块,它依赖于my/cart及my/inventory。磁盘上各文件分布如下:
    · my/cart.js
    · my/inventory.js
    · my/shirt.js
    模块函数以参数‘cart’及‘inventory’使用这两个以‘./cart’及‘./inventoty’名称指定的模块
    在这两个模块加载完毕之前,模块函数不会被调用
    严重不鼓励模块定义全局变量,遵循此处的定义模式,可以使得同一模块的不同版本并存于同一
    页面上,另外,函参的顺序应与依赖顺序保存一致
    返回的object定义了'my/shirt'模块,这种定义模式下,‘my/shirt’不作为一个全局变量而存在
    4、将模块定义为一个函数:
    对模块的返回值类型并没有强制为一定是个object,任何函数的返回值都是允许的,此处是一个返
    回了函数的模块定义:
    define(['my/cart','my/inventory'],function(cart,inventory){
    return function(title){
    return title?(window.title=title):inventory.storeName +'' +cart.name;
    }
    })
    5、简单包装CommonJS来定义模块
    如果你现有一些以CommonJS模块格式编写的代码,而这些代码难于使用上述依赖名称数组参数的形式
    来重构,你可以考虑直接将这些依赖对应到一些本地变量中进行使用,你可以使用一个CommonJS的简
    单包装来实现:
    define(function(require,exports,module){
    var a = require('a'),
    b = require('b');
    return function(){};
    })
    该包装方法依靠Function.prototype.toString()将函数内容赋予一个有意义的字串值,但在一些设备
    如PS3及一些老的Opera手机浏览器中不起作用,考虑在这些设备上使用优化器将依赖导出为数组形式
    6、定义一个命名模块:
    你可以会看到一些define()中包含了一个模块名称作为首个参数:
    define('foo/title',['my/cart','my/inventory'],function(cart,inventory){

    })
    这些常由优化工具生成,你也可以自己显示指定模块名称,但这使模块更不具备移植性--就是说若你
    将文件移动到其他目录下,你就得重命名,一般最好避免对模块硬编码,而是交给优化工具去生成,
    优化工具需要生成模块名以将多个模块打成一个包,加快到浏览的载入速度
    其他注意事项:
    一个文件一个模块:每个JavaScript文件应该只定义一个模块,这是模块名-至-文件名查找机制的
    自然要求。多个模块会被优化工具组织优化,但你在使用优化工具时,应将多个模块放置到一个文件中
    define()中的相对模块名:为了可以在define()内部使用诸如require('./relative/name')的调用以
    正确解析相对名称,记得将‘require’本身作为一个依赖诸如到模块中:
    define(['require'.'./relative/name'],function(require){
    var mod = require('./ralative/name');
    })
    或者更好地,使用下述为转换CommonJS模块所设的更短的语法:
    define(function(require){
    var mod = require('./relative/name');
    })
    相对路径在一些场景下格外有用,例如:为了以便于将代码共享给其他人或项目,你在某个目录下创建
    了一些模块,你可以访问模块的相邻模块,无需知道该目录的名称,
    生成相对于模块的URL地址:你可能需要生成一个相对于模块的URL地址,你可以将'require'作为一个依赖
    注入进来,然后调用require.toUrl()以生成该URL:
    define(['require'],function(require){
    var cssUrl = require.toUrl('./style.css');
    })
    控制台调试:如果你需要处理一个已通过require(['module/name'],function(){})
    调用加载了的模块,可以使用模块名作为字符串参数的require()调用来获取它:
    require('module/name').callSomeFunction()
    注意这种形式仅在“module/name”已经由其异步形式的require(['module/name'])加载
    了后才有效,只能在define内部使用形如“./module/name”的相对路径

    循环依赖:
    如果你定义了一个循环依赖(a依赖b,b同时依赖a),则在这种情形下当b的模块函数被
    调用的时候,它会得到一个undefined的a,b可以在模块已经定义好后用require()方法再获取
    (记得将require作为依赖注入进来):
    define(['require','a'],function(require,a){
    return function(title){
    return require('a').doSomething();
    }
    })
    一般说来你无需使用require()去获取一个模块,而是应当使用注入到模块函数中的依赖。
    循环依赖比较罕见,这也是一个重构代码重新设计的警示灯,但不管怎样,有时候还是要
    用到循环依赖,这种情形下就使用上述的require()方式来解决。

    如果你熟悉CommonJS,你可以考虑使用exports为模块建立一个空object,该object可以立即
    被其他模块引用,在循环依赖的两头都如此操作之后,你就可以安全地持有其他模块了,这种
    方法仅在每个模块都是输出object作为模块值的时候有效,换成函数无效

    define(function(require,exports,module){
    var a = require('a');
    exports.foo = function(){
    return a.bar();
    }
    })

    或者,如果你使用依赖注入数组的步骤,则可用注入特殊的"exports"来解决

    二、requireJS的升级发生的变化:
    1、延迟模块的执行:以前模块加载后factory立马执行,性能上肯定会有一些损耗,现在可以等到
    require的时候才执行
    2、config增加了shim、map、module、enforceDefine
    shim参数解决了使用非AMD方式定义的模块(如jQuery插件)及其载入顺序,使用shim参数来取代
    1.0版本的order插件其实在1.0版本中就曾经有人开发过use和wrap插件来解决此类问题,考虑到很
    多开发者有此类需求(比如某些JS模块是较早时候其他人开发的,非AMD方式)此次2.0版本直接将其
    内置其中

    下面是一个使用jQuery插件形式配置的参数,我们知道jQuery插件本质上是将命名空间挂在全局的jQuery
    或jQuery.fn上,而非使用define定义的 模块,而jQuery插件都依赖于jQuery,即在require插件时得保证
    jQuery先下载下来,可以如下配置:
    require.config({
    shim:{
    'jquery-slide':['jquery']
    }
    });
    require(['jquery-slide'],function(){

    })
    这时会保证下下载jquery.js,然后在下载jquery-slide.js

    map参数用来解决同一模块的不同版本问题,这一灵感来自于Dojo的packageMap。有这样的场景:
    开发初期使用了的jquery-1.6.4,后期升级到了1.7.2,但担心有些依赖jquery-1.6.4的代码升级到
    1.7.2后有问题,因此保守的让这部分代码继续使用1.6.4版本,这时map参数将派上用场。假如A,B
    模块中使用了jquery-1.6.4.js,C,D模块中使用了jquery-1.7.2.js。如下:
    require.config({
    map:{
    'A':{
    'jquery':'jquery-1.6.4'
    },
    'B':{
    'jquery':'jquery-1.7.4'
    }
    }
    })

    require(['A'])将会下载jquery-1.6.4,require(['B'])会下载jquery-1.7.2。如果模块A写成*
    则表示除了B模块使用jquery-1.7.2之外其他模块都是用jquery-1.6.4,map参数解决了模块的各
    个版本问题,很好的向下兼容了老代码

    config参数用来给指定的模块传递一些有用的数据,如下;
    require.config({
    config: {
    'A':{
    info : {name :'jack'}
    }
    }
    })
    使用A的模块中可以通过A.config().info获取到该数据信息。如
    require(['A'],function(A){
    var info = A.config().info;
    console.log(info);
    })

    enforceDefine用来强制模块使用define定义,默认为false,如underscore不再支持AMD后
    其代码移除了define,此时如果仍然使用requirejs来载入他, 他就是普通的js文件了,此时
    如果enforceDefine设为true,虽然underscore.js能下载,但requirejs会报错,
    require函数增加了第三个参数errbacks
    很明显该函数指模块文件没有载入成功时的回调
    require(['b'],function(){
    console.log('success')
    },function(err){
    console.log(err)
    })
    err会给出一些出错提示信息

    更强大的paths参数:
    可以配置成一个数组,顺序映射,当前面的路径没有成功载入,可以接着使用后面的路径
    require.config({
    enforceDefine:true,
    paths:{
    jquery:[
    'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min',
    'lib/jquery'
    ]
    }
    })

    require(['jquery'],function($){

    })

    在模块载入失败回调中可以使用undef函数移除模块的注册:
    require(['jquery'],function($){

    },function(err){
    var failedId = err.requireModules && err.requireModules[0];
    if(failId === 'jquery'){
    requirejs.undef(failedId)
    }
    })

    二、压缩

    压缩:
    node r.js -o baseUrl=js name=main out=built.js
    -o表示优化,该参数是固定的,必选
    baseUrl值存放模块的跟目录,这里是r4/js,因为cd到r4中了,只需设置为js,可选,如果没有设置将从
    r4中查找main.js,
    main 模块的入口文件,这里设置成main,那么r.js会从baseUrl+main去查找,这里实际是r4/js/main.js
    找出其所依赖的所有其他模块,然后合并压缩
    out 指合并压缩后输出的文件路径,这里直接是built.js,那么输出到根目录r4下

    2个参数:
    excludeShallow 合并时将排除该文件
    node r.js -o baseUrl=js name=main out=built.js excludeShallow=selector

    optimize(none/uglify/closure)指定是否压缩,默认为uglify
    不传该参数时r.js默认以uglifyJS压缩,设置为none则不会压缩,仅合并,这在开发阶段是很有用的

    node r.js -o baseUrl=js name=main out=built.js optimize=none
    这时生成的built.js是没有压缩的

    工作并不只是为了那点工资,而是为了创造一份属于自己的事业
  • 相关阅读:
    如何反编译Python写的exe到py
    Liunx常用查找,授权,启动命令
    判断ArrayList集合内是否包含某个元素
    SpringApplicationBuilder作用,以及设置跨域请求过滤器,字符编码,打war包用tomcat运行
    JSON数据解析:Gson(谷歌)和fastjson(阿里巴巴)的异同
    转载:docker安装mycat
    转载:sqlserver 开启快照
    windows 开启操作系统审核策略功能,并设置日志保留不少于180天
    mysql数据库表同步命令
    macos 忘记开机密码,重设密码
  • 原文地址:https://www.cnblogs.com/zouer/p/5072306.html
Copyright © 2020-2023  润新知