AMD&CMD&RequireJS

1. 为什么要使用模块化?

  • 随着 Web2.0时代的到来,,Ajax 技术得到广泛应用,jQuery 等前端库层出不穷,前端的业务逻辑越来越多,代码也越来越多,导致出现了一些问题:
    • 命名冲突:如果引用的js文件很多,无法保证不与其他js文件的变量名或者函数名起冲突。
    //a.js中
     function log(message){
     }
    //b.js中
     function log(message){
     }
    
    • 依赖关系不好管理:如果b.js依赖a.js,标签的书写顺序必须如下所示,当开发人员多起来,需要引用别人的js文件时,很难统一管理。
    <script type="text/javascript" src="a.js"></script>
    <script type="text/javascript" src="b.js"></script>
    
    • 如果一个 js 文件里有太多的实现效果代码,会使得代码体积过于庞大,在出现错误时,难以找到对应的错误代码。
  • 所以我们要使用模块化,来提高代码的可读性,一个模块对应一个功能,也对应一个文件,查找某个功能即可以找到对应的模块。调用的时候也很方便,代码解耦可以提高复用性,不用重复定义功能。

2. CMD、AMD、CommonJS 规范分别指什么?有哪些应用?

  • CommonJS:第一个流行的模块化规范由服务器端的JavaScript应用带来,CommonJS 规范是由 NodeJS 发扬光大,这标志着 JavaScript 模块化编程正式登上舞台。
    • CommonJS 规范包含以下内容
      1. 模块的标识应遵循的规则(书写规范)。
      2. 定义全局函数require,通过传入模块标识来引入其他模块,执行的结果即为别的模块暴漏出来的API。
      3. 如果被 require 函数引入的模块中也包含依赖,那么依次加载这些依赖。
      4. 如果引入模块失败,那么require函数应该报一个异常。
      5. 模块通过变量exports来向往暴漏API,exports只能是一个对象,暴漏的API须作为此对象的属性。。
    • 示例应用如下:
     // moduleA.js
     module.exports = function( value ){
         return value * 2;
     }
    
    // moduleB.js
    var moduleA = require('./moduleA');
    var result = moduleA(4);
    
    • 上面的代码,require 是同步的。模块系统需要同步读取模块文件内容,并编译执行以得到模块的接口,但是这在浏览器端实现却会遇到很多问题。浏览器端,加载 JavaScript 最佳、最容易的方式是在 document 中插入script标签。但脚本标签天生异步,传统 CommonJS 模块在浏览器环境中无法正常加载。于是便需要用一套标准模板来封装模块定义。
  • AMD:即 Asynchromous Module Defination,中文是异步模块定义的意思,他就是浏览器端模块化开发的规范。由于不是 JavaScript 原生支持,使用 AMD 规范进行页面开发需要用到对应的库函数,也就是大名鼎鼎
    RequireJS。
    • requireJS主要解决两个问题
      1. 多个 js 文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器
      2. js 加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长
    • requireJS定义了一个函数 define,它是全局变量,用来定义模块
      define(id?, dependencies?, factory);
      
      1. id:可选参数,用来定义模块的标识,如果没有提供该参数,脚本文件名(去掉拓展名)。
      2. dependencies:是一个当前模块依赖的模块名称数组.
      3. factory:工厂方法,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值。
    • 在页面上使用 require 函数加载模块
      require([dependencies], function(){});
      
      1. 第一个参数是一个数组,表示所依赖的模块。
      2. 第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块。
    • 示例应用如下:
      define('myModule', ['jquery'], function($) {
      // $ 是 jquery 模块的输出
          $('body').text('hello world');
      });
      // 使用
      require(['myModule'], function(myModule) {})
      
    • require()函数在加载依赖的函数的时候是异步加载的,这样浏览器不会失去响应,它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。
  • CMD:即Common Module Definition,通过模块定义。AMD有个RequireJS,CMD有个浏览器实现的SeaJS,SeaJS要解决的问题和RequireJS一样,只不过在模块定义方式和模块加载(可以说运行、解析)时机上有所不同。
    • Sea.js 推崇一个模块一个文件,遵循统一的写法
      define(id?, deps?, factory)
      
      1. 一个文件一个模块,所以经常就用文件名作为模块id。
      2. CMD推崇依赖就近,所以一般不在define的参数中写依赖,在factory中写。
      3. factory有三个参数
      function(require, exports, module)
      
      • require是一个方法,接受模块标识作为唯一的参数,用来获取其他模块提供的接口。
      • exports是一个对象,用来向外提供模块的接口。
      • module是一个对象,上面存储了与当前模块相关联的属性和方法。
    • 示例应用如下:
    // 定义模块 myModule.js
    define(function(require, exports, module) {
        var $ = require('jquery.js')
        $('div').addClass('active');
    });
    
    // 加载模块
    seajs.use(['myModule.js'], function(my){});
    
  • AMD与CMD区别
    • AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块。
    • CMD推崇就近依赖,只有在用到某个模块的时候再去require。
    • AMD和CMD最大的区别是对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同。
    • 很多人说 RequireJS 是异步加载模块,SeaJS 是同步加载模块,这么理解实际上是不准确的,其实加载模块都是异步的,只不过AMD依赖前置,js可以方便知道依赖模块是谁,立即加载,而CMD就近依赖,需要使用把模块变为字符串解析一遍才知道依赖了那些模块,这也是很多人诟病CMD的一点,牺牲性能来带来开发的便利性,实际上解析模块用的时间短到可以忽略

3. 使用 RequireJS 完成以下要求,包括如下功能:

 1. 首屏大图为全屏轮播
 2. 有回到顶部功能
 3. 图片区使用瀑布流布局(图片高度不一),下部有加载更多按钮,点击加载更多会加载更多数据(数据在后端 mock)
 4(可选).  使用 r.js 打包应用

推荐阅读更多精彩内容

  • 为什么要使用模块化? 最主要的目的:解决命名冲突依赖管理 其他价值提高代码可读性代码解耦,提高复用性 CMD、AM...
    Eazer阅读 154评论 2 1
  • 题目1: 为什么要使用模块化? 最主要的目的:1.解决命名冲突2.依赖管理其他价值:1.提高代码可读性2.代码解耦...
    saintkl阅读 52评论 0 0
  • 题目1: 为什么要使用模块化? 最主要的目的:解决命名冲突依赖管理 其他价值:提高代码可读性代码解耦,提高复用性 ...
    Taaaaaaaurus阅读 27评论 0 0
  • 1. 为什么要使用模块化? 背景:如今CPU、浏览器性能得到了极大的提升,很多页面逻辑迁移到了客户端(表单验证等)...
    _李祺阅读 115评论 0 0
  • 身边的朋友渐渐的开始了结婚生子,女人之间的攀比也愈见明显。 ---------------------------...
    天空中的鱼阅读 49评论 0 1