模块化requireJS

(1)首先想到的是函数封装。
但是函数封装有问题,污染了全局变量,无法保证不与其他模块发生冲突。
而且模块之间没有什么关系。

(2)对象的形式
可以把模块成员封装在一个函数中。这样我们可以调用模块是,引入不同的文件,
然后调用相应的函数即可。这样避免了变量污染,只要保证模块名称唯一就可。
看似不错,但是有个问题,外部可以随意改动内部成员。就会有安全问题。

(3)立刻执行函数
通过立刻执行函数,可以达到隐藏细节,不暴露隐私的问题。(function())();

这个就是JS现在模块化的基础。CMD和AMD

首先是CommonJS
nodejs的引入,某种程度上,就标志了js模块化时代的来临。

定义模块:根据CommonJS的规范,一个单独的文件就是一个模块,每一个模块都是一个单独的
作用域,也就是说,该模块内部的变量,就是内部变量,外部无法获取,除非是global对象属性。

模块输出:模块有一个出口,module.exports对象,

加载模块:使用require方法,该方法,读取一个文件,并执行,
返回文件内部的module.exports对象。

例子:
	//模块定义 myModel.js

	var name = 'test';

	function printName(){
		console.log(name);
	}

	function printFullName(firstName){
		console.log(firstName + name);
	}

	module.exports = {
		printName: printName,
		printFullName: printFullName
	}

	//加载模块

	var nameModule = require('./myModel.js');

	nameModule.printName();

上面的例子是同步实现的,require是同步的,模块系统同步读取模块文件内容,并执行。得到相应接口。

浏览器端,加载JavaScript最佳、最容易的方式是在document中插入script标签。

但脚本标签天生异步,传统CommonJS模块在浏览器环境中无法正常加载。

现有2种解决思路,
第一个是:服务器端的组件,对代码进行分析,然后随同http请求,返回给web页面
第二个是:写一个标准模板进行封装定义,然后再对模板进行解析和加载


OK,这样就引出了两种加载方式。AMD和CMD

AMD是"异步模块定义",但是原生JS明显不是很支持这个,就有了RequireJS

RequireJS解决了2个问题:

首先是文件依赖关系,多个JS之间可能存在相互关系,可能要保证执行顺序,所以,将早于依赖它的文件加载到浏览器中。

其次是,js文件加载,会使浏览器会停止渲染,加载文件越多,页面失去响应时间越长,

例子:
	// 定义模块 Module.js
	define(['dependency'], function(){
		var name = 'Byron';
		function printName(){
			console.log(name);
		}

		function add(x, y) {
			return x + y;
		}

		return {
			printName: printName,
			add : add
		};
	});

	// 加载模块
	require(['Module'], function (my){
		my.printName();
		my.add(1, 2);
	});

my.add()与Module模块加载不是同步的,浏览器不会发生假死。所以很显然,AMD比较适合浏览器环境。


requireJS定义了一个函数 define,它是全局变量,用来定义模块
define([id], [dependencies], factory)
id: 可选参数,用来定义模块的标识,如果没有提供参数,脚本文件名,就去掉扩展名
dependencies:是一个当前模块以来的模块名称数组。
factory: 工厂方法,模块初始化要是真的函数或者对象,如果为函数,它应该被执行一次,
如果是对象,此对象应该为模块的输出值。

这里有问,需要学习一下,这里,如果采取同步加载的话,导致了一个问题,因为模块注定都是在服务器上等待被请求,
所以,客户端请求服务器,如果网络很慢,就要等待很久。

require()函数接受两个参数
第一个参数是一个数组,表示所依赖的模块
第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,
从而在回调函数内部就可以使用这些模块

require()函数在加载依赖的函数的时候是异步加载的,这样浏览器不会失去响应,它指定的回调函数,
只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。

写一个完整的requireJS的例子。
(1)test.html文件
<!DOCTYPE html>
<html>
<head>
	<title>test</title>
	<script data-main="js/app.js" src="js/require.js"></script>
</head>
<body>

</body>
</html>

(2)model.js文件
define(function (){
    var add = function (x,y){
      return x+y;
    };
    return {
      add: add
    };
});

(3)app.js文件。
requirejs.config({
    //默认情况下模块所在目录为js/lib
    baseUrl: 'js',
    //当模块id前缀为app时,他便由js/app加载模块文件
    //这里设置的路径是相对与baseUrl的,不要包含.js
    paths: {
        app: 'model.js'
    }
});

// 开始逻辑.
requirejs(['model'], function (nameModule) {
	alert(nameModule.add(1, 2));
});

执行以后,会打印3.


为什么要使用require.js,因为加载多个javascript文件,加载的时候,浏览器会停止渲染,
加载的文件越多,页面失去响应的时间就越长,其次,js之间存在相互关系,必须严格保证加载顺序,
依赖性大的模块一定要放在后面加载。当依赖关系复杂的时候,代码的可维护性变得困难。


require.js为了解决2个问题。
(1)实现js的异步加载,避免网页失去响应
(2)管理各个模块之间的依赖性,便于代码的编写和维护。

使用:
a。首先去下载require.js


b。引入require.js;

<script src="js/require.js" defer async="true" ></script>
async表明这个文件需要异步加载,避免网页失去响应。IE不支持async,而支持defer。

c.加载自己的代码
<script src="js/require.js" data-main="js/main"></script>
假定,代码是main.js,放到js目录下面。
data-main属性的作用是,指定网页程序的主模块。在上例中,就是js目录下面的main.js,
这个文件会第一个被require.js加载。由于require.js默认的文件后缀名是js,所以可以把main.js简写成main。

d,主模块的写法,main.js。这是整个网页的入口代码,类似于c语言的main函数。
这里遵循AMD规范,引入了A,B,C三个模块。而function回调函数中,对应着三个变量,就是模块所对应的。  
但是,触发回调函数的基础是,模块异步加载成功以后。
// main.js
  require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
    // some code here
  })

浏览器异步加载模块A,B,C。浏览器不会失去响应。

e. require.config有几种写法。
一:写绝对路径
  require.config({
    paths: {
      "jquery": "lib/jquery.min",
      "underscore": "lib/underscore.min",
      "backbone": "lib/backbone.min"
    }
  });

二,写baseUrl,写基本路径。
require.config({
    baseUrl: "js/lib",
    paths: {
      "jquery": "jquery.min",
      "underscore": "underscore.min",
      "backbone": "backbone.min"
    }
  });

三,如果模块在另一个主机上面,写个链接地址,比如CND
require.config({
    paths: {
      "jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min"
    }
  });

f。采用AMD规范,就要写define方法

(1)如果定义的模块不依赖于其他模块,就直接define就好
比如:
<!-- math.js -->
define(function () {
var add = function (x, y) {
reuturn x + y;
};

retrun {
add:add
};

});

<!-- main.js -->这里直接调用就可以了,
  require(['math'], function (math){
    alert(math.add(1,1));
  });

(2)如果依赖模块,就将依赖的模块加载。

define(['math'], function(math){
    function foo(x, y, z){
return math.add(x, y) + z;
    }
    return {
      foo : foo
    };
  });
当require()函数加载上面这个模块的时候,就会先加载math.js文件。

最后一个例子

(1)test.html
<!DOCTYPE html>
<html>
<head>
	<title>test
	</title>
	<script data-main="js/app.js" src="js/require.js"></script>
</head>
<body>

</body>
</html>

data-main="js/app.js"	设定了app,js是入口文件。

(2)model.js
define(function (){
    var add = function (x,y){
      return x+y;
    };
	alert(' function model add');
    return {
      add: add
    };
});


(3)test.js;依赖于model模块
define(['model'], function(model){
	function foo(x, y, z){
		return model.add(x, y) + z;
	}

	function fun(x, y, z) {
		return model.add(x, y) - z;
	}

	return {
		foo : foo,
		fun : fun
	};
});
(4)app.js

requirejs.config({
    //默认情况下模块所在目录为js/lib
    baseUrl: 'js',
    //当模块id前缀为app时,他便由js/app加载模块文件
    //这里设置的路径是相对与baseUrl的,不要包含.js
    paths: {
        'model'	: 'model',
        'test' 	: "test"
    }
});

// 开始逻辑.
requirejs(['model', 'test'], function (nameModule, test) {
  alert(nameModule.add(1, 2));
  alert(test.fun(1,2,3));
});

//加载了model和test模块。

// 开始逻辑.
requirejs(['test'], function ( test) {
  alert(test.fun(1,2,3));
});


注意:这里的 model 模块,只加载了一次,虽然第二次调用test时好,依旧会调用model,
但是只加载一次。test模块,它依赖于model,但是依旧只调用了一次。

/*************************************************************/
之前加载的都是规范的AMD格式的模块,现在加载一些非规范的模块
比如underscore和backbone。都没有采用AMD的方式,如果加载的话,需要定义config

require.config({
    shim: {

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

这个对象除了有前面说过的paths属性之外,还有一个shim属性,专门用来配置不兼容的模块。
具体来说,每个模块要定义
(1)exports值(输出的变量名),表明这个模块外部调用时的名称;
(2)deps数组,表明该模块的依赖性。

requirejs插件。
https://github.com/jrburke/requirejs/wiki/Plugins

原文地址:https://www.cnblogs.com/hgonlywj/p/4853989.html