AMD范例(转)

1. AMD的由来
  前端手艺虽然在不停发展当中,却一向没有质的奔腾。除了已有的各大有名框架,比方Dojo,jQuery,ExtJs等等,很多公司也都有着自身的前端开辟框架。这些框架的运用效力以及开辟质量在很大水平上都取决于开辟者对其的熟习水平,以及对JavaScript的熟习水平,这也是为何很多公司的手艺带头人都喜好开辟一个自身的框架。开辟一个自身会用的框架并不难,但开辟一个人人都喜好的框架却很难。从一个框架迁移到一个新的框架,开辟者很有可以还会依据原有框架的头脑去思索和解决题目。这个中的一个主要原因就是JavaScript自身的灵活性:框架没办法相对的束缚你的行动,一件事变总可以用多种门路去完成,所以我们只能在要领学上去指导准确的实行要领。光荣的是,在这个层面上的软件要领学研讨,一向有人在去不停的尝试和革新,CommonJS就是个中的一个主要构造。他们提出了很多新的JavaScript架构计划和范例,愿望能为前端开辟供应银弹,供应一致的指引。

  AMD范例就是个中比较有名一个,全称是Asynchronous Module Definition,即异步模块加载机制。从它的范例形貌页面看,AMD很短也很简朴,但它却完全形貌了模块的定义,依靠关联,援用关联以及加载机制。从它被requireJS,NodeJs,Dojo,JQuery运用也可以看出它具有很大的代价,没错,JQuery近期也采用了AMD范例。在这篇文章中,我们就将引见AMD的性子,用法,上风以及运用场景。从AMD中我们也能进修到如安在更高层面去设想自身的前端运用。

2. AMD是什么
 >  作为一个范例,只需定义其语法API,而不关心其完成。AMD范例简朴到只要一个API,即

define函数:
define([module-name?], [array-of-dependencies?], [module-factory-or-object]);

个中:

  module-name: 模块标识,可以省略。

  array-of-dependencies: 所依靠的模块,可以省略。

  module-factory-or-object: 模块的完成,或许一个JavaScript对象。

  从中可以看到,第一个参数和第二个参数都是可以省略的,第三个参数则是模块的详细完成自身。背面将引见在差别的运用场景下,他们会运用差别的参数组合。

  从这个define函数AMD中的A:Asynchronous,我们也不难想到define函数具有的别的一个性子,异步性。当define函数实行时,它首先会异步的去挪用第二个参数中列出的依靠模块,当一切的模块被载入完成以后,假如第三个参数是一个回调函数则实行,然后通知体系模块可用,也就通知了依靠于自身的模块自身已可用。假如对应到dojo1.6之前的完成,那末在功用上可以有以下对应关联:

  

    module-name: dojo.provide

  dependencies: dojo.require

  module-factory: dojo.declare

  差别的是,在加载依靠项时,AMD用的是异步,而dojo.require是同步。异步和同步的区分不言而喻,前者不会壅塞浏览器,有更好的机能和灵活性。而关于NodeJs如许的服务器端AMD,则模块载入无需壅塞服务器历程,一样进步了机能

3,AMD实例:怎样定义一个模块
  下面代码定义了一个alpha模块,而且依靠于内置的require,exports模块,以及外部的beta模块。可以看到,第三个参数是回调函数,可以直接运用依靠的模块,他们按依靠声明递次作为参数供应给回调函数。

  这里的require函数让你可以随时去依靠一个模块,即获得模块的援用,从而纵然模块没有作为参数定义,也可以被运用;exports是定义的alpha 模块的实体,在其上定义的任何属性和要领也就是alpha模块的属性和要领。经由过程exports.verb = …就是为alpha模块定义了一个verb要领。例子中是简朴挪用了模块beta的verb要领。

  

define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {

  exports.verb = function() {

  return beta.verb();

  //或许:

  return require("beta").verb();

  }

  });

4. 匿名模块
  define 要领许可你省略第一个参数,如许就定义了一个匿名模块,这时刻模块文件的文件名就是模块标识。假如这个模块文件放在a.js中,那末a就是模块名。可以在依靠项顶用”a”来依靠于这个匿名模块。这带来一个优点,就是模块是高度可重用的。你拿来一个匿名模块,随意放在一个位置便可以运用它,模块名就是它的文件途径。这也很好的相符了DRY(Don’t Repeat Yourself)准绳。

  下面的代码就定义了一个依靠于alpha模块的匿名模块:
  

define(["alpha"], function (alpha) {

  return {

  verb: function(){

  return alpha.verb() + 2;

  }

  }; 

  });

5. 唯一一个参数的define
  前面提到,define的前两个参数都是可以省略的。第三个参数有两种状况,一种是一个JavaScript对象,另一种是一个函数。

  假如是一个对象,那末它多是一个包含要领具有功用的一个对象;也有多是仅供应数据。后者和JSON-P异常相似,因而AMD也可以以为包含了一个完全的 JSON-P完成。模块演变为一个简朴的数据对象,如许的数据对象是高度可用的,而且由于是静态对象,它也是CDN友爱的,可以进步JSON-P的机能。斟酌一个供应中国省市对应关联的JavaScript对象,假如以传统JSON-P的情势供应给客户端,它必需供应一个callback函数名,依据这个函数名动态天生返回数据,这使得范例JSON-P数据肯定不是CDN友爱的。但假如用AMD,这个数据文件就是以下的情势:

  

define({

  provinces: [

  {

  name: '上海',

  areas: ['浦东新区', '徐汇区']},

  {

  name: '江苏',

  cities: ['南京', '南通']} 

  //.....

  ]

  });

  假定这个文件名为china.js,那末假如某个模块须要这个数据,只须要:

  

define(['china', function(china){

  //在这里运用中国省市数据

  });

  经由过程这类体式格局,这个模块是真正高度可复用的,无论是用长途的,照样Copy到当地项目,都勤俭了开辟时刻和保护时刻。

  假如参数是一个函数,其用处之一是疾速开辟完成。适用于较小型的运用,你无需提早关注自身须要什么模块,自身给谁用。在函数中,可以随时require自身须要的模块。比方:

  

define(function(){

  var p = require('china');

  //运用china这个模块

  });

  即你省略了模块名,以及自身须要依靠的模块。这不意味着你无需依靠于其他模块,而是可以让你在须要的时刻去require这些模块。define要领在实行的时刻,会挪用函数的toString要领,并扫描个中的require挪用,提早协助你载入这些模块,载入完成以后再实行。这使得疾速开辟成为可以。须要注重的一点是,Opera不能很好的支撑函数的toString要领,因而,在浏览器中它的适用性并非很强。但假如你是经由过程build东西打包一切的 JavaScript文件,这将不是题目,构建东西会协助你扫描require并强迫载入依靠的模块。

6. Dojo中的AMD
  Dojo 的1.6版本,个中一个主要的变化就是引入了AMD机制,庖代了本来的dojo.provide和dojo.require要领。然则如今依然坚持了向后兼容性,你依然可以用dojo.provide和dojo.require来定义和加载模块。须要注重的是:在 Dojo 1.6 中, 针对 AMD 的重构依然属于一个过渡期的修改 , 用户自身开辟的 AMD 模块还不能被 Dojo 的加载器和 Build 体系支撑 . 1.6 中现有的编译体系对AMD的支撑还异常范围。 假如你自身开辟了 AMD 花样的模块,而且你依然在运用默许的 Dojo 同步模块加载器,那末你必需严厉遵照 Dojo 模块的花样 ( 包含换行的花样 ) 来保证你自身的模块可以胜利编译。总结起来有以下三点:

  用传统的要领 (dojo.require()/dojo.provide()) – 这些模块,只能被 Dojo 同步加载器 加载,但可以被 Dojo 编译体系(Build System )准确的编译

  用 Dojo 同步加载器来加载 AMD 花样 ( define ()) 模块 – 这些模块可以被平常的加载,而且可以被其他兼容 AMD 花样的加载器加载 . 如今虽然 Dojo1.6 还没有正式支撑这类用法, 但在现在的 Dojo1.6 编译体系中,是可以平常事情的 . ( 条件是你必需严厉遵照 Dojo 模块定义的代码范例 )

  运用第三方加载器来加载 AMD 花样( define ())模块 – 模块可以被平常加载,而且可以被其他加载器所运用 . 这些模块可以运用 RequireJS 或 Backdraft 供应的编译体系平常编译,然则 Dojo 还没有正式的测试过和其他加载器的兼容性 .

  以Calendar为例,用define要领来定义这个模块:

  

define("dijit/Calendar",

  ["dojo", "dijit", "text!dijit/templates/Calendar.html",

  "dojo/cldr/supplemental", "dojo/date", "dojo/date/locale",

  "dijit/_Widget", "dijit/_Templated", "dijit/_CssStateMixin", "dijit/form/DropDownButton"],

  function(dojo, dijit) {

  dojo.declare(

  "dijit.Calendar",

  [dijit._Widget, dijit._Templated, dijit._CssStateMixin],

  {...}

  );

  return dijit.Calendar;

  }

  );

  可以看到,模块标识就是模块文件的途径,模块自身平常都是dojo.declare定义的类。Dojo1.6中的dojo和dijit定名空间下的模块均已用AMD的情势进行了重构,但dojox下依然延用了传统的dojo.provide和dojo.require情势。对AMD的引入是Dojo走向自动化包治理的主要一步,在后续文章中我们也将继承关注Dojo在这方面的希望。

7. 结论
  AMD 范例是JavaScript开辟的一次主要尝试,它以简朴而文雅的体式格局一致了JavaScript的模块定义和加载机制,并敏捷获得很多框架的承认和采用。这对开辟人员来说是一个好消息,经由过程AMD我们降低了进修和运用种种框架的门坎,可以以一种一致的体式格局去定义和运用模块,进步开辟效力,降低了运用保护本钱。

    原文作者:zone
    原文地址: https://segmentfault.com/a/1190000008390635
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞