require.js实现js模块化编程(一)

时间:2022-09-05 17:45:48

require.js实现js模块化编程(一)

1、认识require.js:

官方文档:http://requirejs.org/
RequireJS是一个非常小巧的JavaScript模块载入框架,是AMD规范最好的实现者之一。最新版本的RequireJS压缩后只有14K,堪称非常轻量。它还同时可以和其他的框架协同工作,使用RequireJS必将使您的前端代码质量得以提升。
RequireJS 是一个JavaScript模块加载器。它非常适合在浏览器中使用, 但它也可以用在其他脚本环境, 就像 Rhino and Node. 使用RequireJS加载模块化脚本将提高代码的加载速度和质量。

2、require.js的优点:

  • 2.1、异步加载,防止js阻塞页面渲染;
  • 2.2、按需加载,避免在初始化网页的时候,产生大量的请求和数据传输;防止出现如下丑陋的场景:

<script type="text/javascript" src="a.js"></script>
<script type="text/javascript" src="b.js"></script>
<script type="text/javascript" src="c.js"></script>
<script type="text/javascript" src="d.js"></script>

  • 2.3、更加方便的模块依赖管理。相信你曾经一定遇到过因为script标签顺序问题而导致依赖关系发生错误,这个函数未定义,那个变量undefine之类的。通过RequireJS的机制,你能确保在所有的依赖模块都加载以后再执行相关的文件,所以可以起到依赖管理的作用。
  • 2.4、更加高效的版本管理。想一想,如果你还是用的script脚本引入的方式来引入一个jQuery2.x的文件,然后你有100个页面都是这么引用的,那当你想换成jQuery3.x,那你就不得不去改这100个页面。但是如果你的requireJS有在config中做jQuery的path映射,那你只需要改一处地方即可。

 3、在网页中未使用require.js和使用require.js比较

      网页中未使用require.js编写方式:

index.html:

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="a.js"></script>
</head>
<body>
<span>body</span>
</body>
</html>

a.js:

function fun1(){
alert("it works");
}
fun1();

可能你更喜欢这样写:

a.js:

(function(){
function fun1(){
alert("it works");
}
fun1();
})()

第二种方法使用了块作用域来申明function防止污染全局变量,本质还是一样的,当运行上面两种例子时不知道你是否注意到,alert执行的时候,html内容是一片空白的,即<span>body</span>并未被显示,当点击确定后,才出现,这就是JS阻塞浏览器渲染导致的结果。
    使用require.js写法:

index.html

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="require.js"></script>
<script type="text/javascript">
require(["a"]);
</script>
</head>
<body>
<span>body</span>
</body>
</html>

a.js

define(function(){
function fun1(){
alert("it works");
}
fun1();
})

浏览器提示了"it works",说明运行正确,但是有一点不一样,这次浏览器并不是一片空白,body已经出现在页面中。

4、熟悉requirejs基本API
require会定义三个变量:define,require,requirejs,其中require === requirejs,一般使用require更简短;
一个回调函数:callback

  • ● define 从名字就可以看出这个api是用来定义一个模块
  • ● require 加载依赖模块,并执行加载完后的回调函数
  • ● callback,一个function,是用来处理加载完毕后的逻辑

用define定义模块的方法如下:【function定义法】
如果index.html,main.js,js文件夹为平级目录,a.js和jquery.js位于js文件夹下,
 a.js【AMD规范的写法】

define(function() {
var target = null;
function countTool() {
target = this;
target.value = 0;
};
countTool.prototype.add = function(a, b) {
return a + b;
};
countTool.prototype.minus = function(a, b) {
return a - b;
};
return countTool;
});

用require 加载依赖模块,没有用到callback回调函数,方法如下:

main.js

require(["js/a"]);

来加载该模块(注意require中的依赖是一个数组,即使只有一个依赖,你也必须使用数组来定义).
require API的第二个参数是callback,一个function,是用来处理加载完毕后的逻辑,如:

main.js

require(["js/a"],function(countTool){
countTool.add(2,3);
})

会得到结果为:5
如上的写法,我们发现require()第一个数组的参数中,添加的a.js的写法["js/a"]较繁琐。但可以使用require.config()来进行优化。

5、用require.config()来加载文件
之前的例子中加载模块都是本地js,但是大部分情况下网页需要加载的JS可能来自本地服务器、其他网站或CDN,这样就不能通过这种方式来加载了,我们以加载一个jquery库为例:

main.js

require.config({
paths : {
"jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery"],
// paths还可以配置多个路径,如果远程cdn库没有加载成功,可以加载本地的库,如下:
// "jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery", "js/jquery"],
"a" : "js/a"
}
})
require(["jquery","a"],function($,a){
$(function(){
a.add(2,3); // 5
})
})

在使用requirejs时,加载模块时不用写.js后缀的,当然也是不能写后缀

6、requirejs的使用方法

  • 6.1、首先要到requirejs的网站去下载js ->requirejs.org或者到我的网盘下载
  • 6.2、然后在index.html页面中使用下面的方式来使用requirejs
 <script data-main="js/main" src="js/require.js" defer async="true"></script>

  相关参数解析如下:

(1)、加载requirejs脚本的script标签加入了data-main属性,是指当reuqire.js加载完成之后,就可以使用这个配置文件(main.js)来直接使用require来加载所有的短模块名。
(2)、当script标签指定data-main属性时,require会默认的将data-main指定的js为根路径,是什么意思呢?如上面的data-main="js/main"设定后,我们在使用require(['jquery'])后(不配置jquery的paths),require会自动加载js/jquery.js这个文件,而不是jquery.js,相当于默认配置了:

require.config({
baseUrl : "js"
})

(3)、async属性表明这个文件需要异步加载,避免网页失去响应。
(4)、IE的异步加载,只支持defer,所以把defer也写上。

  • 6.3、添加全局配置文件main.js

注意:前提是需要在js/libs文件夹下放入jquery.js和a.js,并且a.js要实现AMD规范的写法,参照上面的a.js.

main.js

require.config({
paths : {
"jquery" : "./libs/js/jquery",
"a" : ".libs/js/a"
}
})
require(["jquery","a"],function($,a){
console.log($);
a.add(2,3); // 5
})

另外一种优化paths的方法为:使用参数baseUrl,前提是js/jquery.js,js/a.js如下:另外一种优化paths的方法为:使用参数baseUrl,前提是js/jquery.js,js/a.js如下:

main.js

require.config({
  baseUrl: "js/lib",
  paths: {
    "jquery": "jquery",
    "a": "a"
  }
});
require(["jquery","a"],function($,a){
console.log($);
a.add(2,3); // 5
})
  • 6.4、a.js实现AMD规范的写法

require.js加载的模块,采用AMD规范。也就是说,模块必须按照AMD的规定来写。
具体来说,就是模块必须采用特定的define()函数来定义。如果一个模块不依赖其他模块,那么可以直接定义在define()函数之中。
require定义一个模块是通过 define = function (name, deps, callback)完成的,第一个参数是定义模块名,第二个参数是传入定义模块所需要的依赖,第三个函数则是定义模块的主函数,主函数和require的回调函数一样,同样是在依赖加载完以后再调用执行。

如下,没有依赖模块的写法。假定现在有一个a.js文件,它定义了一个a模块。那么,a.js就要这样写:

a.js 写法一: 直接定义方法

 define(function (){
// 加法
    var add = function (x,y){
      return x+y;
    };
// 减法
var minus = function(x,y){
return x-y;
}
    return {
      add: add,
minus:minus
    };
  });

a.js 写法二: 方法衍生法

define(function() {
var target = null;
function countTool() {
target = this;
target.value = ;
};
countTool.prototype.add = function(a, b) {
return a + b;
};
countTool.prototype.minus = function(a, b) {
return a - b;
};
return countTool;
});

a.js 写法三: 对象定义法

define(function() {
var module = {};
module.value = ;
//加法
var add = function(a, b) {
return a + b;
}
//减法
var minus = function(a, b) {
return a - b;
}
module.add = add;
module.minus = minus;
return module;
});

加载方法如下:

main.js

require(['a'], function (a){
  alert(a.add(1,1)); // 2
});

如果这个模块还依赖其他模块,那么define()函数的第一个参数,必须是一个数组,指明该模块的依赖性。
依赖对象定义,如: b.js,假设b.js中定义乘法和除法方法。

define(['./b'], function(b) {
var module = {};
var add = a.add; //加法
var minus = a.minus; //减法
var multi = b.multi; // 乘法
var division = b.division; // 除法 module.add = add;
module.minus = minus;
module.multi = multi ;
module.division = division; return module;
});

当require()函数加载上面这个模块的时候,就会先加载a.js文件。

为什么我始终都没有使用name来定义自己的模块名:
如果你细心,你可能会发现,刚刚define函数,有一个参数name是用来定义模块名的(也就是第一个传参),为什么上面两个例子都没有用到。其实我确实可以添加模块名,如下:

define('b',['./b'],function(b){
.....
})

但是,这样做感觉不很有必要,因为如果哪一天我将这个文件转移到其他目录下,那我就得在这这里再修改一次模块名。官方其实也不推荐,用官方的说法是:让优化工具去自动生成这些模块名吧!

  • 6.5、加载非规范化模块

理论上,require.js加载的模块,必须是按照AMD规范、用define()函数定义的模块。但是实际上,虽然已经有一部分流行的函数库(比如jQuery)符合AMD规范,更多的库并不符合。那么,require.js是否能够加载非规范的模块呢?
回答是可以的。

那么如何判断一个js库,有没有采用AMD规范?只需看其js库中,有没有实现define.amd相关的判断代码即可;
如jQuery中实现AMD的代码如下:

 if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function() {
return jQuery;
} );
}

underscore.js v1.6中AMD的代码如下:

 if (typeof define === 'function' && define.amd) {
define('underscore', [], function() {
return _;
});
}

jQuery 从 1.7 版本开始支持了 AMD 对其类库的加载,所以开发者可以通过 require 方法来异步加载 jQuery 的源代码。
underscore.js从1.6,backbone.js从1.1.1版本之后开始支持了 AMD 对其类库的加载;
例如,如果用到underscore.js v1.6或者backbone.js v1.1.1之前的版本,这样的模块在用require()加载之前,要先用require.config()方法,定义它们的一些特征。这里需要用到shim{},专门用来配置不兼容的模块,如下:

require.config({
  shim: {
      'underscore':{
        exports: '_'
      },
      'backbone': {
        deps: ['underscore', 'jquery'],
        exports: 'Backbone'
      },
'jquery.scroll': {
       deps: ['jquery'],
       exports: 'jQuery.fn.scroll'
     }
  }
});

如:dateUtil.js,没有用define()来定义。

(function(window) {
var DateUtils = {};
DateUtils.toString = function() {
alert("toString");
};
// 全局变量
window.DateUtils = DateUtils;
})(window);

加载该模块的方法如下:

require.config({
shim:{
dateUtil:{
deps:[],
exports:'dateUtil'
}
}
});

具体来说,每个模块要定义
(1)deps数组,表明该模块的依赖性。
(2)exports值(输出的变量名),表明这个模块外部调用时的名称;

7、require.js提供了一个优化工具r.js

require.js提供了一个优化工具r.js或者到网盘下载,当模块部署完毕以后,可以用这个工具将多个模块合并在一个文件中,减少HTTP请求数。
具体使用方法,请参考下节:require.js实现js模块化编程(二):RequireJS Optimizer

8、相关文档:

require.js,实现具体的项目构建,请自行下载,谢谢关注。

require.js实现js模块化编程(一)的更多相关文章

  1. 应用require&period;js进行javascript模块化编程小试一例

    长久以来都渴望应用javascript的模块化编程.今日紧迫更甚,岁月蹉跎,已经不能再等了. 拜读阮一峰的有关文章已经好几遍,文章写得真好,简洁流畅,头头是道,自觉有点明白了.但经验告诉我们,一定要亲 ...

  2. 从273二手车的M站点初探js模块化编程

    前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数 ...

  3. Javascript模块化编程(三):require&period;js的用法

    Javascript模块化编程(三):require.js的用法 原文地址:http://www.ruanyifeng.com/blog/2012/11/require_js.html 作者: 阮一峰 ...

  4. Javascript模块化编程之路——&lpar;require&period;js&rpar;

    转自:http://www.ruanyifeng.com/blog/2012/10/javascript_module.html Javascript模块化编程(一):模块的写法 随着网站逐渐变成&q ...

  5. require&period;js实现js模块化编程(二):RequireJS Optimizer

    require.js实现js模块化编程(二):RequireJS Optimizer 这一节,我们主要学习一下require.js所提供的一个优化工具r.js的用法. 1.认识RequireJS Op ...

  6. javascript模块化编程库require&period;js的用法

    随着javascript的兴起,越来越多的公司开始将JS模块化,以增加开发的效率和减少重复编写代码的.更是为了能更加容易的维护日后的代码,因为现在的随着人们对交互效果的越来越强烈的需求,我们的JS代码 ...

  7. 坑人的 Javascript 模块化编程 require&period;js

    坑人的 Javascript 模块化编程 require.js

  8. Javascript模块化编程require&period;js的用法

    JS模块化工具requirejs教程(一):初识requirejs http://www.runoob.com/w3cnote/requirejs-tutorial-1.html JS模块化工具req ...

  9. &lpar;转&rpar;Javascript模块化编程(三):Require&period;js的用法

    转自 ruanyifeng 系列目录: Javascript模块化编程(一):模块的写法 Javascript模块化编程(二):AMD规范 Javascript模块化编程(三):Require.js的 ...

随机推荐

  1. Spring&period;net 间接调用被AOP拦截的方法失效(无法进入aop的拦截方法)

    .下面的tx要定义 <objects xmlns="http://www.springframework.net" xmlns:db="http://www.spr ...

  2. MongoDB&lpar;3&rpar;&colon;小的细节问题

    1.文档 {“greeting”:“hello,world”,“foo”: 3} 文档中的键/值对是有序的,下面的文档与上面的文档是完全不同的两个文档. {“foo”: 3 ,“greeting”:“ ...

  3. js学习笔记之包装对象

    JavaScript包装对象 近日有时间,闲下来好好学习原生js JavaScript是一门面向对象语言,使用"."就可以访问对象的属性和方法,而基本类型(null, undefi ...

  4. &lpar;转&rpar;Facade模式

    Facade模式要求一个子系统的外部与其内部的通信必须通过一个统一的Facade对象进行.Facade模式提供一个高层次的接口,使得子系统更易于使用. 就如同医院的接待员一样,Facade模式的Fac ...

  5. WPF学习(5)依赖属性

    今天我们来学习WPF一个比较重要的概念:依赖属性.这里推荐大家看看周永恒大哥的文章,讲的确实很不错.我理解的没那么深入,只能发表一下自己的浅见.提到依赖属性,不得不说我们经常使用的传统的.net属性, ...

  6. &lbrack;转&rsqb;C&num;异步的世界【上】

    阅读目录   APM EAP TAP 延伸思考 新进阶的程序员可能对async.await用得比较多,却对之前的异步了解甚少.本人就是此类,因此打算回顾学习下异步的进化史. 本文主要是回顾async异 ...

  7. BOM的使用

    window 对象 BOM 的核心对象是window,它表示浏览器的一个实例.在浏览器中,window 对象有双重角色,它既是通过JavaScript 访问浏览器窗口的一个接口,又是ECMAScrip ...

  8. iOS开发线程安全问题

    先来看一下代码: - (void)viewDidLoad { [super viewDidLoad]; self.testStr = @"String initial complete&qu ...

  9. 【Unix网络编程】chapter5TCP回射服务器程序

    chapter5  5.1 概述 5.2 TCP回射服务器程序:main函数 int main(int argc, char **argv) { int listenfd,connfd; pid_t ...

  10. 2017-2018-2 20155233『网络对抗技术』Exp6:信息收集与漏洞扫描

    通过DNS和IP挖掘目标网站的信息 whois查询:用来进行域名注册信息查询,以得到3R注册信息,包括注册人的名字.组织.城市等信息.(进行whois查询时去掉www等前缀,因为注册域名时通常会注册一 ...