zoukankan      html  css  js  c++  java
  • 模块化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

  • 相关阅读:
    虚拟主机wordpress文件上传大小限制更改
    wordpress网站迁移
    JavaScript算法相关
    文章阅读(三)
    文章阅读(二)
    Image():强制让图片缓存起来
    JavaScript运算符与类型
    JavaScript权威指南--多媒体和图形编程
    JavaScript权威指南--脚本化HTTP
    JavaScript权威指南--事件处理
  • 原文地址:https://www.cnblogs.com/hgonlywj/p/4853989.html
Copyright © 2011-2022 走看看