require.js 最佳实践

稿件来源: 互联网   撰稿作者: 太阳光   发表日期: 2015-06-29   阅读次数: 63   查看权限: 游客查看

require.js 最佳实践

1. require.js的主要作用是js的工程化,规范化:

1)它是一个js脚本的加载器,它遵循AMD(Asynchronous Module Definition)规范,实现js脚本的异步加载,不阻塞页面的渲染和其后的脚本的执行。

    并提供了在加载完成之后的执行相应回调函数的功能;

2)它要求js脚本的模块化,也就是文件化;require.js的作用之一就是加载js模块,也就是js文件。所以我们的js的书写应该模块化,也就是文件化。

3)它可以管理js模块/文件之间的依赖; js模块化,文件化之后,它们之间的依赖可以通过require.js优雅的解决;

4)require.js中提供的优化器 r.js 可以来优化页面中的js脚本和css文件,达到提高页面响应速度,减少页面所需要的http/https请求次数。在极端优化的情况下,通过r.js优化 之后的页面只需要一次js脚本请求和一次CSS文件请求。这就极大的减少了页面所需要的http/https请求的次数,提高了页面的加载速度。r.js 的优化分为两种方式:一是压缩js和css文件,也就是去掉空格,空行,将长变量名换成短变量名之类的;二是合并多个js文件为一个js文件,合并多个css文件为一个

5) 通过使用require.js之后,我们只需要在页面引入一行<script>标签,类似于:<script src="js/require.js" data-main="js/login.js"></script>,甚至也可以只引入一行<style>标签,十分优 雅。注意引入一行<script>标签并不等价于只需要一次js的http/https的请求。

2. require.js模块的写法:

require.js要求我们的js模块,也就是js文件按照一定的格式书写:也就是最好通过define()函数来写js模块,比如:math.js

define(function(){
    var add = function(x,y){
        return x+y;
    };
    return{
        add:add
    };
});

math.js通过define()函数,定义了一个符合require.js要求的js模块,它的返回值是一个对象,有一个属性add,它是一个函数。通过下的方式就可以来调用该js模块中定义的函数:

require.config({
    baseUrl:"/ems/js/",
    paths:{
        "math":"math"
    }
});
 
require(["math"], function(math){
    alert(math.add(100,20));
});

require.config的主要作用是配置 模块ID/模块名称 和 它对应的js文件所在的位置。上面的那个配 置就是将 /ems/js/math.js(ems是项目名称) 文件配置成一个ID为math的模块,然后通过 require(["math"], function(math)(){}); 就可以异步来加载 /ems/js/math.js 文件,加载完成之后,执行回调函数。回调函数中调用了math模块中的add方法。

看一个例子(文件名:dateUtil.js):

define(function(){
    var dateFormat = function(fmt, date){
        if(!(date instanceof Date))
            return;
        var o = {
                "M+": date.getMonth() + 1, // 月份
                "d+": date.getDate(), //日
                "H+": date.getHours(), //24小时制
                "h+" : date.getHours()%12 == 0 ? 12 : date.getHours()%12, //12小时制 
                "m+": date.getMinutes(), //分
                "s+": date.getSeconds(), //秒
                "q+": Math.floor((date.getMonth() + 3) / 3), //季度
                "S": date.getMilliseconds()  //毫秒
            };
            if (/(y+)/.test(fmt))
                fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
            for (var k in o)
            if (new RegExp("(" + k + ")").test(fmt))
                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k])
                                    : (("00" + o[k]).substr(("" + o[k]).length)));
            return fmt;
    };
     
    return {
        format:dateFormat
    };
});

通过下面的配置,就可以使用dataUtil.js中的format()函数来格式化日期对象:

require.config({
    baseUrl:"/ems/js/",
    paths: {
        "dateUtil": "dateUtil"     
    }  
});
 
require(["dateUtil"], function(dateUtil){
   alert(dateUtil.format("yyyy-MM-dd", new Date());
});

我们在页面中引入上面的文件(文件名:main.js),就可以看到执行效果:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
      <span>body1111</span>
<script src="js/require.js" data-main="js/main.js"></script>
</body>
</html>

3. require.config函数

require.config如上面所说,主要是定义 模块ID 和 它所对应的js文件的位置。参数是一个json格式的对象,baseUrl属性指定paths中的路径的相对路径。paths是一个key/value的 键值对形式,key表示模块ID,value表示相对于baseUrl的相对路径,需要省略文件后缀 .js 。还有一个shim的常用属性,用来配置不符合require.js规范的js模块(没有使用define()来书写),使之也能被我们的 require()函数来使用。但是shim配置的模块,无法通过cnd使用。其使用方法参见前面的转载文章。

4. require()函数

require.config({
    paths: {
        "jquery": "jquery.min",
        "math":"math",
        "dateUtil":"dateUtil"
    }
});
 
require(['jquery', 'math', "dateUtil" ], function ($, math, dateUtil){
    alert($("span").text());
    alert(math.add(1,30));
    alert(dateUtil.format("yyyy-MM-dd", new Date()));
});

require()函数,第一个参数,引入依赖的require模块, 在所有依赖异步加载完成之后,将这些模块的返回的对象或者返回的函数传入回调函数,那么在回调函数中就可以使用这些被依赖的模块的功能了。比如上面使用 math.add(1,30)。

5. r.js 优化(合并压缩js和CSS文件)

按照require方式进行模块化之后,必然会产生很多的js文件,它们通过环环相扣的方式,按照依赖关系异步加载,那么必然会导致js文件所需要 的http/https请求极大的增加,这时,就应该使用 r.js 来优化了。它可以将一个页面比如 login.jsp, 需要的所有的js文件合并成一个js文件也就是说只需要一次http/https请求就行了。所以就解决了js模块化之后http/https请求增多的问题,并且还减少到了只需要一次请求。同时r.js还可以压缩js文件。并且正对css文件也可以同样的方式减小合并压缩。优化一般在开发完成之后,发布之前进行。

1)js文件合并压缩:

比如开发时,某页面如下:

<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="css/bootstrap.min.css" />
<link rel="stylesheet" href="css/matrix-login.css" />
<link rel="stylesheet" href="css/bootstrap-responsive.min.css" />
</head>
<body>
<!--Header-part-->
<div id="header">
  <h1><a href="javascript:;">Admin</a></h1>
</div>
<!--close-Header-part-->
 
<!--top-Header-menu-->
<div id="user-nav" class="navbar navbar-inverse">
  <ul class="nav">
    <li class=""><span id="top_header">xxxx系统</span></li>
    <li><span id="cur_user">当前登陆用户:</span></li>
    <li id="top_logout" style="float:right;">
        <a href="${ctx}/logout"><i class="icon icon-share-alt"></i></a>
    </li>
  </ul>
</div>
<script src="js/require.min.js" data-main="js/main.js"></script>
</body>
</html>

其main.js文件如下:

require.config({   
    baseUrl:"/emsjs/",
    paths: {       
        "jquery":"jquery.min",
        "dateUtil":"dateUtil"
    }
});
 
require(['jquery','dateUtil'], function ($, dateUtil){
    // ...
});

那么显然该页面有 3个 CSS文件,2个js文件。那么针对js文件,我们可以使用node.js来合并:

$ node r.js -o baseUrl=js name=main out=login.js

下面对命令行做个简单解释。
node r.js -o baseUrl=js name=main out=built.js

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

我们看到将 jquery.js, dateUtil.js, main.js 三个文件合并压缩成了一个文件:login.js, 那么我们在页面中就只需要引入login.js文件就行了。

<script src="js/require.min.js" data-main="js/main.js"></script>
//改成:
<script src="js/require.min.js" data-main="js/login.js"></script>

再介绍两个参数:

1,excludeShallow 合并时将排除该文件

假如我们要排除selector.js
node r.js -o baseUrl=js name=main out=built.js excludeShallow=selector

2,optimize (none/uglify/closure)  指定是否压缩,默认为uglify
不传该参数时r.js默认以UglifyJS压缩。设置为none则不会压缩,仅合并,这在开发阶段是很用用的。
node r.js -o baseUrl=js name=main out=built.js optimize=none

特别注意:对 于path配置的非本地的模块文件,使用r.js合并压缩时需要配置paths.xx=empty。比如上面的jQuery引用的是 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min'那么打包时需要剔除 出去,否则报错。
$node r.js -o baseUrl=js name=main out=login.js path.jquery=empty

2) CSS文件合并压缩:

合并压缩之前,需要先定义一个main.css文件:

@import url(bootstrap.min.css);
@import url(bootstrap-responsive.min.css);
@import url(matrix-login.css);

然后调用命令合并压缩:

$ node r.js -o cssIn=css/main.css out=login.css optimizeCss=standard

四个CSS文件合并成了一个css文件:login.css。我们看下压缩之后的login.css:

//上面三行CSS的link:

<link rel="stylesheet" href="css/bootstrap.min.css" />
<link rel="stylesheet" href="css/matrix-login.css" />
<link rel="stylesheet" href="css/bootstrap-responsive.min.css" />

//就可以换成一行:

<link rel="stylesheet" href="css/login.css" />

还可以使用optimizeCss参数设置来配置是否压缩及压缩选项。optimizeCss的取值有standard/none /standard.keepLines/standard.keepComments /standard.keepComments.keepLines。

none  不压缩,仅合并

standard  标准压缩 去换行、空格、注释

standard.keepLines  除标准压缩外,保留换行

standard.keepComments  除标准压缩外,保留注释

standard.keepComments.keepLines  除标准压缩外,保留换行和注释

示例:

node r.js -o cssIn=css/main.css out=css/built.css optimizeCss=standard

6. require.js 最佳实践

前面说了那么多,最后才说到require.js的最佳实践。

1)使用 define() 定义符合require规范的模块;

2)使用require.config() 配置模块ID和它对应的js模块所在文件路径;require.config()是将define()定义的模块和require()依赖的模块连接起来;

3)使用require()指定其所依赖的模块,在回调中实现页面上需要的功能,当然define()函数也需要指定其所依赖的模块;

     require()和define()函数其实十分相似,都指定依赖的模块,都有回调函数;

4)使用r.js合并优化。这里最重要。合并优化涉及到一个取舍问题,比如前面的 jquery.min.js 是否应该被合并进去呢?因为jquery.min.js是一个通用的js库文件,那么其实几乎每一个页面都需要改文件,那么其实我们只是在第一次访问该网 站时,需要下载一次jquery.min.js文件,其后使用的都是缓存中的,status都是304;但是如果我们每个页面都将 jquery.min.js 合并进该页面的唯一的 js 文件,那么jquery.min.js就会被每个页面所下载,因为每个页面都合并了它。个人是觉得不应该将jquery.min.js这样的通用库合并进 去的,而是应该放入cnd中,这样既不会受到浏览器访问同一个域名时,并发数量的限制,也可以使其能够被缓存。但是 304 好像也是需要发送一次http/https请求的?所以如何取舍呢?CSS文件bootstrap.min.css也遇到相似的取舍问题。

最后还有一个build.js中可以配置很多其它参数,可以在这个示例文件中找到更多配置选项,相关知识请另查文档学习!

关键词: javascript,require,模块化   编辑时间: 2015-06-29 15:28:06

  • 感到高兴

    0

    高兴
  • 感到支持

    0

    支持
  • 感到搞笑

    0

    搞笑
  • 感到不解

    0

    不解
  • 感到谎言

    0

    谎言
  • 感到枪稿

    0

    枪稿
  • 感到震惊

    0

    震惊
  • 感到无奈

    0

    无奈
  • 感到无聊

    0

    无聊
  • 感到反对

    0

    反对
  • 感到愤怒

    0

    愤怒
0%(0)
0%(0)
共有0 条评论 发言请遵守【相关规定

网友评论

会员头像
发 表同步腾讯微博    验证码:  点击更新请先登陆
  • 暂无评论
关闭模块文章图片 article Pictrue
  • 我的妈妈爸爸
  • 基于koa2+mysql+vue2.0+Element阳光内容管理系统
  • 代码覆盖率工具 Istanbul 入门教程
  • 全栈工程师的武器——MEAN
  • 9款超炫的 CSS3 复选框(Checkbox)
  • 微信开发在线翻译功能
  • CSS3那些不为人知的高级属性
  • 给easyui的datebox添加清空事件
  • flash写字效果
  • kendoUI系列教程之DropDownList下拉菜单
  • kendoUI系列教程之datetimepicker日期时间选择
  • kendoUI系列教程之datepicker日期选择
  • kendoUI系列教程之combobox下拉列表框
  • kendoUI系列教程之colorpicker
  • kendoUI系列教程之calendar日历表
  • kendoUI系列教程之autocomplete自动补齐