一篇著作通晓RequireJS常用文化,超简单社团AngularJS模块

2018年下半年接触前端开发和AngularJS,一路跌跌撞撞,尤以模块化代码社团的教训最深厚。

一篇作品理解RequireJS常用知识,一篇理解requirejs

正文采纳渐进的方法,从理论到实施,从RequireJS官方API文档中,总结出在动用RequireJS过程中最常用的一对用法,并对文档中不够显著具体的内容,加以例证和分析,分享给我们供我们参考,具体内容如下

1. 模块化
深信每个前端开发人士在刚起首接触js编程时,都写过类似下面这样风格的代码:

<script type="text/javascript">
  var a = 1;
  var b = 2;
  var c = a * a + b * b;

  if(c> 1) {
    alert('c > 1');
  }

  function add(a, b) {
    return a + b;
  }

  c = add(a,b);
</script>

<a href="javascript:;" onclick="click(this);" title="">请点击</a>

这么些代码的特征是:

  • 所在可见的全局变量
  • 大量的函数
  • 内嵌在html元素上的各种js调用

本来这个代码本身在落实效益上并不曾不当,可是从代码的可重用性,健壮性以及可维护性来说,这种编程形式是有题目的,尤其是在页面逻辑较为复杂的应用中,这一个题目会透露地特别领悟:

  • 全局变量极易导致命名顶牛
  • 函数式编程卓殊不便民代码的集体和治本
  • 内嵌的js调用很不便宜代码的维护,因为html代码有的时候是特别重叠和高大的

就此当这一个题材出现的时候,js大牛们就起来探寻去化解这一个题目标究极办法,于是模块化开发就应运而生了。正如模块化这几个概念的表面意思同样,它要求在编制代码的时候,按层次,按效益,将单身的逻辑,封装成可选拔的模块,对外提供直接明了的调用接口,内部贯彻细节完全私有,并且模块之间的里边贯彻在执行期间互不苦恼,最后的结果就是可以化解眼前举例提到的问题。一个简单易行遵照模块化开发要求编辑的事例:

//module.js
var student = function (name) {
    return name && {
        getName: function () {
          return name;
        }
      };
  },
  course = function (name) {
    return name && {
        getName: function () {
          return name;
        }
      }
  },
  controller = function () {
    var data = {};
    return {
      add: function (stu, cour) {
        var stuName = stu && stu.getName(),
          courName = cour && cour.getName(),
          current,
          _filter = function (e) {
            return e === courName;
          };

        if (!stuName || !courName) return;

        current = data[stuName] = data[stuName] || [];

        if (current.filter(_filter).length === 0) {
          current.push(courName);
        }
      },
      list: function (stu) {
        var stuName = stu && stu.getName(),
          current = data[stuName];
        current && console.log(current.join(';'));
      }
    }
  };

//main.js

var stu = new student('lyzg'),
  c = new controller();

c.add(stu,new course('javascript'));
c.add(stu,new course('html'));
c.add(stu,new course('css'));
c.list(stu);

上述代码定义了七个模块分别表示学生,课程和控制器,然后在main.js中调用了controller提供的add和list接口,为lyzg那多少个学生添加了三门课程,然后在控制台突显了出去。运行结果如下:

javascript;html;css

由此上例,可以看看模块化的代码结构和逻辑分外清楚,代码看起来特别优雅,另外由于逻辑都经过模块拆分,所以达到了然耦的目标,代码的意义也会相比健全。然而上例使用的这种模块化开发格局也并不是绝非问题,这么些题材就是它依然把模块引用如student那一个直接助长到了大局空间下,即便经过模块缩短了众多大局空间的变量和函数,不过模块引用我如故要依赖全局空间,才能被调用,当模块较多,或者有引入第三方模块库时,仍旧可能造成命名抵触的问题,所以这种全局空间下的模块化开发的方法并不是最完善的法子。方今大面积的模块化开发格局,全局空间情势是最主旨的一种,另外常见的还有听从AMD规范的开发格局,坚守CMD规范的开发格局,和ECMAScript
6的开发格局。需要证实的是,CMD和ES6跟本文的核心没有涉嫌,所以不会在此介绍,前面的情节重点介绍英特尔以及贯彻了Intel规范的RequireJS。

2. AMD规范
正如上文提到,实现模块化开发的点子,其它常见的一种就是听从Intel规范的实现模式,不过Intel规范并不是实际的兑现情势,而仅仅是模块化开发的一种缓解方案,你能够把它知道成模块化开发的部分接口注解,即便你要贯彻一个坚守该规范的模块化开发工具,就不可以不兑现它预先定义的API。比如它要求在加载模块时,必须利用如下的API调用情势:

require([module], callback)
其中:
[module]:是一个数组,里面的成员就是要加载的模块;
callback:是模块加载完成之后的回调函数

负有遵守AMD规范的模块化工具,都无法不遵照它的渴求去实现,比如RequireJS这些库,就是全然服从Intel规范落实的,所以在采纳RequireJS加载或者调用模块时,假若您事先知道Intel规范的话,你就了然该怎么用RequireJS了。规范的功利在于,不同的贯彻却有同样的调用模式,很容易切换不同的工具使用,至于具体用哪一个实现,这就跟各样工具的独家的亮点跟项目标特色有涉嫌,这一个都是在品种上马选型的时候需要确定的。近日RequireJS不是绝无仅有兑现了AMD规范的库,像Dojo这种更宏观的js库也都有Intel的兑现。

说到底对英特尔全称做一个分解,译为:异步模块定义。异步强调的是,在加载模块以及模块所依靠的此外模块时,都采纳异步加载的艺术,防止模块加载阻塞了网页的渲染进度。相比传统的异步加载,AMD工具的异步加载更加便捷,而且还可以实现按需加载,具体解释在下有些认证。

3. JavaScript的异步加载和按需加载 html中的script标签在加载和施行进程中会阻塞网页的渲染,所以一般要求尽量将script标签放置在body元素的底层,以便加速页面展现的速度,还有一种艺术就是由此异步加载的方法来加载js,这样可以避免js文件对html渲染的不通。

第1种异步加载的主意是一贯动用脚本生成script标签的法门:

(function() {
  var s = document.createElement('script');
  s.type = 'text/javascript';
  s.async = true;
  s.src = 'http://yourdomain.com/script.js';
  var x = document.getElementsByTagName('script')[0];
  x.parentNode.insertBefore(s, x);
})();

这段代码,放置在script标记内部,然后该script标记添加到body元素的底部即可。

第2种方法是依赖script的属性:defer和async,defer这一个特性在IE浏览器和早起的银狐浏览器中帮助,async在支撑html5的浏览器上都辅助,只要有这多少个特性,script就会以异步的措施来加载,所以script在html中的地方就不重大了:

<script defer async="true" type="text/javascript" src="app/foo.js"></script>
<script defer async="true" type="text/javascript" src="app/bar.js"></script>
<script defer async="true" type="text/javascript" src="app/main.js"></script>

这种模式下,所有异步js在履行的时候仍旧按梯次执行的,不然就会设有依靠问题,比如倘使上例中的main.js倚重foo.js和bar.js,可是main.js先实施的话就会出错了。尽管一向理论上这种艺术也算不错了,但是不够好,因为它用起来很麻烦,而且还有个问题就是页面需要丰硕两个script标记以及从未艺术完全形成按需加载。

JS的按需加载分几个层次,首个层次是只加载这一个页面可能被用到的JS,第二个层次是在只在利用某个JS的时候才去加载。传统地情势很容易做到第一个层次,然而不容易形成第二个层次,尽管我们得以经过集合和压缩工具,将某个页面所有的JS都充裕到一个文书中去,最大程度减弱资源请求量,可是这多少个JS请求到客户端将来,其中有为数不少情节恐怕都用不上,倘诺有个工具能够做到在需要的时候才去加载相关js就完美解决问题了,比如RequireJS。

4. RequireJS常用用法总计 前文多次提及RequireJS,本有的将对它的常用用法详细表达,它的合法地址是:http://www.requirejs.cn/,你可以到该地址去下载最新版RequireJS文件。RequireJS作为目前使用最广泛的AMD工具,它的主要优点是:

  • 全然协助模块化开发
  • 能将非Intel规范的模块引入到RequireJS中动用
  • 异步加载JS
  • 完全按需加载倚重模块,模块文件只需要裁减混淆,不需要统一
  • 谬误调试
  • 插件襄助

4.01 怎么样使用RequireJS
使用形式很粗略,只要一个script标记就足以在网页中加载RequireJS:

<script defer async="true" src="/bower_components/requirejs/require.js"></script>

由于这里运用了defer和async这五个异步加载的特性,所以require.js是异步加载的,你把这么些script标记放置在任哪个地点方都并未问题。

4.02
咋样运用RequireJS加载并进行当前网页的逻辑JS

4.01缓解的无非是RequireJS的接纳问题,但它只有是一个JS库,是一个被眼前页面的逻辑所选拔的工具,真正贯彻网页功效逻辑的是我们要运用RequireJS编写的主JS,这么些主JS(如果这么些代码都停放在main.js文件中)又该怎么样行使RJ来加载执行呢?形式如下:

<script data-main="scripts/main.js" defer async="true" src="/bower_components/requirejs/require.js"></script>

相比之下4.01,你会意识script标记多了一个data-main,RJ用这么些布局当前页面的主JS,你要把逻辑都写在这一个main.js里面。当RJ自身加载执行后,就会重新异步加载main.js。这些main.js是近年来网页所有逻辑的进口,理想状态下,整个网页只需要这么些script标记,利用RJ加载依赖的其他文件,如jquery等。

 4.03 main.js怎么写
倘若项目的目录结构为:

图片 1

main.js是跟当前页面相关的主JS,app文件夹存放本项目自定义的模块,lib存放第三方库。

html中按4.02的法门安排RJ。main.js的代码如下:

require(['lib/foo', 'app/bar', 'app/app'], function(foo, bar, app) {
  //use foo bar app do sth
});

在这段JS中,我们运用RJ提供的require方法,加载了六个模块,然后在这么些六个模块都加载成功将来执行页面逻辑。require方法有2个参数,第一个参数是数组类型的,实际利用时,数组的各类元素都是一个模块的module
ID,第二个参数是一个回调函数,这一个函数在率先个参数定义的富有模块都加载成功后回调,形参的个数和顺序分别与第一个参数定义的模块对应,比如首个模块时lib/foo,那么这一个回调函数的首先个参数就是foo那多少个模块的引用,在回调函数中我们运用那么些形参来调用各种模块的主意,由于回调是在各模块加载之后才调用的,所以这个模块引用肯定都是实惠的。

从以上这多少个简单的代码,你应有早就知晓该怎么运用RJ了。

4.04 RJ的baseUrl和module ID
在介绍RJ如何去分析倚重的那一个模块JS的路径时,必须先弄清楚baseUrl和module
ID这两个概念。

html中的base元素可以定义当前页面内部任何http请求的url前缀部分,RJ的baseUrl跟这么些base元素起的效果是相近的,由于RJ总是动态地呼吁看重的JS文件,所以必然关联到一个JS文件的门道解析问题,RJ默认接纳一种baseUrl
+
moduleID的辨析方法,这么些分析方法后续会举例说明。那一个baseUrl异常重大,RJ对它的拍卖服从如下规则:

  • 在未曾应用data-main和config的动静下,baseUrl默认为当前页面的目录
  • 在有data-main的图景下,main.js前面的一部分就是baseUrl,比如下边的scripts/
  • 在有config的情形下,baseUrl以config配置的为准

上述二种艺术,优先级由低到高排列。

data-main的运用办法,你曾经掌握了,config该怎么布置,如下所示:

require.config({
  baseUrl: 'scripts'
});

以此布局必须放置在main.js的最前头。data-main与config配置同时设有的时候,以config为准,由于RJ的其余配置也是在那些地点布置的,所以4.03中的main.js可以改成如下结构,以便将来的扩大:

require.config({
  baseUrl: 'scripts'
});

require(['lib/foo', 'app/bar', 'app/app'], function(foo, bar, app) {
  // use foo bar app do sth
});

有关module
ID,就是在require方法以及持续的define方法里,用在凭借数组那个参数里,用来标识一个模块的字符串。下边代码中的[‘lib/foo’,
‘app/bar’, ‘app/app’]就是一个凭借数组,其中的各样元素都是一个module
ID。值得注意的是,module ID并不一定是该module
相关JS路径的一局部,有的module
ID很短,但可能路径很长,这跟RJ的解析规则有关。下一节详细介绍。

4.05 RJ的文书分析规则
RJ默认按baseUrl + module
ID的条条框框,解析文件,并且它默认要加载的文本都是js,所以您的module
ID里面可以不包含.js的后缀,这就是怎么你见到的module ID都是lib/foo,
app/bar这种格局了。有两种module ID,不适用这种规则:

如果main.js如下使用:

require.config({
  baseUrl: 'scripts'
});

require(['/lib/foo', 'test.js', '/js/jquery'], function(foo, bar, app) {
  // use foo bar app do sth
});

这五个module 都不会基于baseUrl + module ID的条条框框来分析,而是直接用module
ID来分析,等效于上边的代码:

<script src="/lib/foo.js"></script>
<script src="test.js"></script>
<script src="/js/jquery.js"></script>

各样module ID解析举例:

例1,项目协会如下:

图片 2

main.js如下:

require.config({
  baseUrl: 'scripts'
});

require(['lib/foo', 'app/bar', 'app/app'], function(foo, bar, app) {
  // use foo bar app do sth
});

baseUrl为:scripts目录

moduleID为:lib/foo, app/bar, app/app

依照baseUrl +
moduleID,以及机关补后缀.js,末了这六个module的js文件路径为:

scripts/lib/foo.js
scripts/app/bar.js
scripts/app/app.js

例2,项目布局同例1:

main.js改为:

require.config({
  baseUrl: 'scripts/lib',
  paths: {
   app: '../app'
  }
});


require(['foo', 'app/bar', 'app/app'], function(foo, bar, app) {
  // use foo bar app do sth
});

这边出现了一个新的布局paths,它的职能是针对性module
ID中一定的片段,举办转义,如以上代码中对app这多少个有些,转义为../app,这意味一个相对路径,相对地方是baseUrl所指定的目录,由项目结构可知,../app其实对应的是scirpt/app目录。正因为有其一转义的留存,所以上述代码中的app/bar才能被科学解析,否则还按baseUrl
+
moduleID的规则,app/bar不是应该被分析成scripts/lib/app/bar.js吗,但实际上并非如此,app/bar被解析成scripts/app/bar.js,其中起关键功效的就是paths的部署。通过这一个比喻,可以看到module
ID并不一定是js文件路径中的一部分,paths的布置对于路径过程的js特别有效,因为可以简化它的module
ID。

另外第一个模块的ID为foo,同时没有paths的转义,所以基于分析规则,它的公文路径时:scripts/lib/foo.js。

paths的部署中只有当模块位于baseUrl所指定的公文夹的同层目录,或者更上层的目录时,才会用到../那种相对路径。

例3,项目结果同例1,main.js同例2:

此间要验证的问题不怎么特殊,不以main.js为例,而以app.js为例,且app倚重bar,当然config仍然需要在main.js中定义的,由于这多少个问题在概念模块的时候进一步宽广,所以用define来举例,假如app.js模块如下概念:

define(['./bar'], function(bar) {
   return {
     doSth: function() {
       bar.doSth();
     }
   }
});

上边的代码通过define定义了一个模块,那多少个define函数前面介绍怎样定义模块的时候再来介绍,那里大概询问。这里这种用法的首先个参数跟require函数一样,是一个凭借数组,第二个参数是一个回调,也是在具备倚重加载成功之后调用,那一个回调的归来值会成为这一个模块的引用被其它模块所使用。

这边要说的题目要么跟解析规则相关的,如若完全遵循RJ的解析规则,这里的看重性应该配备成app/bar才是天经地义的,但出于app.js与bar.js位于同一个索引,所以完全可利用./那一个同目录的相对标识符来解析js,这样的话只要app.js已经加载成功了,那么去同目录下找bar.js就必然能找到了。这种安排在概念模块的时候特别有意义,这样你的模块就不借助于于放置这个模块的公文夹名称了。

4.06 RJ的异步加载
RJ不管是require方法或者define方法的看重模块都是异步加载的,所以下边的代码不必然能分析到正确的JS文件:

<script data-main="scripts/main" src="scripts/require.js"></script>
<script src="scripts/other.js"></script>
//main.js
require.config({
  paths: {
    foo: 'libs/foo-1.1.3'
  }
});
//other.js
require( ['foo'], function( foo ) {
  //foo is undefined
});

出于main.js是异步加载的,所以other.js会比它先加载,可是RJ的安排存在于main.js里面,所以在加载other.js读不到RJ的部署,在other.js执行的时候解析出来的foo的路径就会变成scripts/foo.js,而不利途径应该是scripts/libs/foo-1.1.3.js。

即使RJ的依赖性是异步加载的,不过已加载的模块在多次借助的时候,不会再重复加载:

define(['require', 'app/bar', 'app/app'], function(require) {
  var bar= require("app/bar");
  var app= require("app/app");
  //use bar and app do sth
});

地点的代码,在callback定义的时候,只用了一个形参,这关键是为着减小形参的多寡,防止一切回调的签约很长。倚重的模块在回调内部可以直接用require(moduleID)的参数获得,由于在回调执行前,看重的模块已经加载,所以这里调用不会再重新加载。可是一旦这里获取一个并不在倚重数组中出现的module
ID,require很有可能获取不到该模块引用,因为它或许需要重新加载,借使它从未在此外模块中被加载过的话。

4.07 RJ官方推荐的JS文件社团结构 RJ指出,文件社团尽量扁平,不要多层嵌套,最美好的是跟项目相关的位于一个文书夹,第三方库位于一个文书夹,如下所示:

图片 3

4.08 使用define定义模块 Intel规定的模块定义规范为:

define(id?, dependencies?, factory);

其中:
id: 模块标识,可以省略。
dependencies: 所依赖的模块,可以省略。
factory: 模块的实现,或者一个JavaScript对象

至于率先个参数,本文不会涉嫌,因为RJ提出所有模块都休想采取第一个参数,倘诺应用第一个参数定义的模块成为命有名的模特块,不适用第一个参数的模块成为匿名模块,命超级模特块假使更名,所有倚重它的模块都得修改!第二个参数是凭借数组,跟require一样,倘使没有这么些参数,那么定义的就是一个无依靠的模块;最后一个参数是回调或者是一个简便对象,在模块加载完毕后调用,当然没有第二个参数,最终一个参数也会调用。

本有的所举例都应用如下项目布局:

图片 4

  1. 概念简单对象模块:

app/bar.js

define({
 bar:'I am bar.'
});
利用main.js测试:
require.config({
  baseUrl: 'scripts/lib',
  paths: {
    app: '../app'
  }
});

require(['app/bar'], function(bar) {
  console.log(bar);// {bar: 'I am bar.'}
});
  1. 概念无依靠的模块:

app/nodec.js:

define(function () {
  return {
    nodec: "yes, I don't need dependence."
  }
});

利用main.js测试:

require.config({
  baseUrl: 'scripts/lib',
  paths: {
    app: '../app'
  }
});

require(['app/nodec'], function(nodec) {
  console.log(nodec);// {nodec: yes, I don't need dependence.'}
});
  1. 概念倚重另外模块的模块:

app/dec.js:

define(['jquery'], function($){
  //use $ do sth ...
  return {
    useJq: true
  }
});

利用main.js测试:

require.config({
  baseUrl: 'scripts/lib',
  paths: {
    app: '../app'
  }
});

require(['app/dec'], function(dec) {
  console.log(dec);//{useJq: true}
});
  1. 巡回看重:
    当一个模块foo的借助数组中留存bar,bar模块的依赖性数组中设有foo,就会形成巡回倚重,稍微修改下bar.js和foo.js如下。

app/bar.js:

define(['foo'],function(foo){
 return {
 name: 'bar',
 hi: function(){
  console.log('Hi! ' + foo.name);
 }
 }
});

lib/foo.js:

define(['app/bar'],function(bar){
 return {
 name: 'foo',
 hi: function(){
  console.log('Hi! ' + bar.name);
 }
 }
});

利用main.js测试:

require.config({
  baseUrl: 'scripts/lib',
  paths: {
    app: '../app'
  }
});


require(['app/bar', 'foo'], function(bar, foo) {
  bar.hi();
  foo.hi();
});

运作结果:

图片 5

若果改变main.js中require部分的依赖性顺序,结果:

图片 6

巡回依赖导致六个依靠的module之间,始终会有一个在拿到另一个的时候,得到undefined。解决模式是,在概念module的时候,就算用到循环信赖的时候,在define内部通过require重新得到。main.js不变,bar.js改成:

define(['require', 'foo'], function(require, foo) {
  return {
    name: 'bar',
    hi: function() {
     foo = require('foo');
      console.log('Hi! ' + foo.name);
    }
  }
});

foo.js改成:

define(['require', 'app/bar'], function(require, bar) {
  return {
    name: 'foo',
    hi: function() {
     bar = require('app/bar');
      console.log('Hi! ' + bar.name);
    }
  }
});

接纳上述代码,重新履行,结果是:

图片 7

模块定义总括:不管模块是用回调函数定义仍然简单对象定义,这一个模块输出的是一个引用,所以那么些引用必须是行得通的,你的回调无法重临undefined,可是不局限于对象类型,还足以是数组,函数,甚至是着力项目,只不过如果回去对象,你能透过那么些目标社团更多的接口。

4.09 内置的RJ模块
再看看这多少个代码:

define(['require', 'app/bar'], function(require) {
  return {
    name: 'foo',
    hi: function() {
      var bar = require('app/bar');
      console.log('Hi! ' + bar.name);
    }
  }
});

依傍数组中的require这么些moduleID对应的是一个置于模块,利用它加载模块,怎么用你早就阅览了,比如在main.js中,在define中。另外一个松开模块是module,这么些模块跟RJ的此外一个部署有关,具体用法请在第5多数去领悟。

4.10 其余RJ有用功效 1. 变通相对于模块的URL地址

define(["require"], function(require) {
  var cssUrl = require.toUrl("./style.css");
});

这多少个功用在你想要动态地加载一些文书的时候有用,注意要利用相对路径。

  1. 控制台调试

require(“module/name”).callSomeFunction() 假如你想在控制武汉查阅某个模块都有什么样措施能够调用,假如那一个模块已经在页面加载的时候经过依赖被加载过后,那么就足以用上述代码在控制布Rhys托做各个测试了。

5. RequireJS常用配置总计 在RJ的布置中,前边已经触发到了baseUrl,paths,另外多少个常用的配备是:

  • shim
  • config
  • enforceDefine
  • urlArgs

5.01 shim
为那一个并未动用define()来声称依赖关系、设置模块的”浏览器全局变量注入”型脚本做依赖和导出配置。

例1:利用exports将模块的全局变量引用与RequireJS关联

main.js如下:

require.config({
  baseUrl: 'scripts/lib',
  paths: {
    app: '../app'
  },
  shim: {
   underscore: {
   exports: '_'
   }
  }
});

require(['underscore'], function(_) {
  // 现在可以通过_调用underscore的api了
});

如您所见,RJ在shim中添加了一个对underscore那一个模块的配置,并通过exports属性指定该模块表露的全局变量,以便RJ可以对这多少个模块统一保管。

例2:利用deps配置js模块的借助

main.js如下:

require.config({
  baseUrl: 'scripts/lib',
  paths: {
    app: '../app'
  },
  shim: {
   backbone: {
    deps: ['underscore', 'jquery'],
    exports: 'Backbone'
   }
  }
});

require(['backbone'], function(Backbone) {
  //use Backbone's API
});

鉴于backbone这多少个组件依赖jquery和underscore,所以可以透过deps属性配置它的依赖,这样backbone将会在此外五个模块加载完毕之后才会加载。

例3:jquery等库插件配置情势

代码举例如下:

requirejs.config({
  shim: {
    'jquery.colorize': {
      deps: ['jquery'],
      exports: 'jQuery.fn.colorize'
    },
    'jquery.scroll': {
      deps: ['jquery'],
      exports: 'jQuery.fn.scroll'
    },
    'backbone.layoutmanager': {
      deps: ['backbone']
      exports: 'Backbone.LayoutManager'
    }
  }
});

5.02 config
时常需要将安排音讯传给一个模块。这个安排往往是application级此外信息,需要一个招数将它们向下传递给模块。在RequireJS中,基于requirejs.config()的config配置项来促成。要拿到这一个音讯的模块可以加载特殊的依靠“module”,并调用module.config()。

例1:在requirejs.config()中定义config,以供其他模块使用

requirejs.config({
  config: {
    'bar': {
      size: 'large'
    },
    'baz': {
      color: 'blue'
    }
  }
});

如您所见,config属性中的bar这一节是在用于module
ID为bar这多少个模块的,baz这一节是用于module
ID为baz这些模块的。具体使用以bar.js举例:

define(['module'], function(module) {
  //Will be the value 'large'var size = module.config().size;
});

前边提到过,RJ的嵌入模块除了require还有一个module,用法就在此处,通过它能够来加载config的内容。

5.03 enforceDefine 即便设置为true,则当一个剧本不是通过define()定义且不拥有可供检查的shim导出字串值时,就会抛出荒唐。这些特性可以强制要求具备RJ倚重或加载的模块都要因此define或者shim被RJ来保管,同时它还有一个益处就是用来错误检测。

5.04 urlArgs
RequireJS获取资源时增大在URL后边的附加的query参数。作为浏览器或服务器未正确配置时的“cache
bust”手段很有用。使用cache bust配置的一个示范:

urlArgs: “bust=” + (new Date()).getTime()
6. 错误处理
**
6.01 加载错误的抓获
**IE中捕获加载错误不周到:

IE
6-8中的script.onerror无效。没有艺术判断是否加载一个脚本会导致404错;更甚地,在404中如故会触发state为complete的onreadystatechange事件。
IE
9+中script.onerror有效,但有一个bug:在实施脚本之后它并不触发script.onload事件句柄。由此它不可以支撑匿名AMD模块的正统方法。所以script.onreadystatechange事件仍被使用。不过,state为complete的onreadystatechange事件会在script.onerror函数触发在此之前接触。
之所以为了匡助在IE中捕获加载错误,需要配置enforceDefine为true,这不得不要求您具备的模块都用define定义,或者用shim配置RJ对它的引用。

留意:尽管您设置了enforceDefine:
true,而且你采纳data-main=””来加载你的主JS模块,则该主JS模块必须调用define()而不是require()来加载其所需的代码。主JS模块依然可调用require/requirejs来设置config值,但对此模块加载必须利用define()。比如原本的这段就会报错:

require.config({
 enforceDefine: true,
  baseUrl: 'scripts/lib',
  paths: {
    app: '../app'
  },
  shim: {
   backbone: {
   deps: ['underscore', 'jquery'],
      exports: 'Backbone'
   }
  }
});
require(['backbone'], function(Backbone) {
  console.log(Backbone);
});

把最终三行改成:

define(['backbone'], function(Backbone) {
  console.log(Backbone);
});

才不会报错。

6.02 paths备错

requirejs.config({
  //To get timely, correct error triggers in IE, force a define/shim exports check.
  enforceDefine: true,
  paths: {
    jquery: [
      'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min',
      //If the CDN location fails, load from this location
      'lib/jquery'
    ]
  }
});

//Later
require(['jquery'], function ($) {
});

上述代码先品尝加载CDN版本,假使出错,则退回到地头的lib/jquery.js。

留神:
paths备错仅在模块ID精确匹配时工作。那不同于常规的paths配置,常规配置可配合模块ID的人身自由前缀部分。备错重要用以分外的荒谬复苏,而不是正规的path查找分析,因为那在浏览器中是无效的。

6.03 全局 requirejs.onError 为了抓获在局域的errback中未捕获的要命,你能够重载requirejs.onError():

requirejs.onError = function (err) {
  console.log(err.requireType);
  if (err.requireType === 'timeout') {
    console.log('modules: ' + err.requireModules);
  }

  throw err;
};

如上就是本文的全部内容,希望对我们的学习抱有襄助。

最开头代码量小也没经验,直接在html引用所有js文件。后来搞得html文件进一步大,js的一一一乱,就报奇奇怪怪的一无是处,找半天。

你或许感兴趣的篇章:

  • LABjs、RequireJS、SeaJS的区别
  • SeaJS 与 RequireJS 的差距相比较
  • JavaScript的RequireJS库入门指南
  • 优化RequireJS项目标有关技术总括
  • 动用RequireJS优化JavaScript引用代码的形式
  • 在JavaScript应用中使用RequireJS来兑现延迟加载
  • RequireJS入门一之实现率先个例子
  • 小心!AngularJS结合RequireJS做文件合并压缩的那个坑

http://www.bkjia.com/Javascript/1096181.htmlwww.bkjia.comtruehttp://www.bkjia.com/Javascript/1096181.htmlTechArticle一篇文章掌握RequireJS常用知识,一篇掌握requirejs
本文采纳渐进的艺术,从理论到实施,从RequireJS官方API文档中,总括出在使用RequireJ…

其次个门类,我就想着要改进,直奔声名显赫的RequireJS去了。但RequireJS真的很忙碌有木有!平添了很多代码,和AngularJS的Dependency
Injection长得还挺像,一不小心就搞混。时不时报个Script
Error出来,根本不亮堂问题在何地。

有没有更简约的不二法门呢?正想着呢,ng-newsletter一声炮响,送来了这篇著作。作者Jeff
Dickey
介绍了用模块来组织代码的四种方法,依据推荐程度,依次为:

  • Require.js (Implementation of AMD)
  • Browserify (Implementation of CommonJS)
  • Angular dependency injection
  • ES6 modules

笔者着重写了在第三种基础上,社团代码的简化方法(捂脸,我才用到第一种)。

模块的遵循,首先是要切断命名空间。Angular的模块机制很好地解决了。除了angular这个目的自我,没有其他表露在Global里的靶子。

接下来是处理倚重关系。Angular的模块同样指定了依靠关系,而Dependency
Injection在更细的粒度上做了类似的事。

更棒的是,Angular模块的定义顺序可以任由。各种service、controller、directive注册到模块的一一,也未曾范围。唯一的要求只是:模块要先定义,后采用。请看上面的例证:

// 模块可以按任意的顺序定义
angular.module('app', ['ctrl']);
angular.module('ctrl', ['svc']);
angular.module('svc', []);

// 使用尚未注册的GithubSvc
angular.module('ctrl')
.controller('GithubCtrl', function ($scope, GithubSvc) {
  GithubSvc.fetchStories().success(function (users) {
    $scope.users = users;
  });
});

angular.module('svc')
.factory('GithubSvc', function ($http) {
  return {
    fetchStories: function () {
      return $http.get('https://api.github.com/users');
    }
  };
});

可运行的代码在这么些jsFiddle

Angular没有帮我们缓解的,就剩下文件加载了。既然加载顺序无关首要,这直接把文件合并起来不就好了?反正最后都要联合的。

gulp.task('js', function () {
  gulp.src(['src/**/module.js', 'src/**/*.js'])
    .pipe(concat('app.js'))
    .pipe(gulp.dest('.'))
})

无论按工作或者按效益区划目录,只要把每个模块的定义都坐落目录下的module.js里,保证拥有模块在采用以前都早就定义过了,直接concat毫无问题。html里却唯有一行:

<script src="app.js"></script>

编制、测试依旧按模块分目录和文书,代码协会清晰利落。拼接到一起在浏览器上跑。发表时,再ngAnnotateuglify一晃就好。

库的代码,再拼出一个vender.js就行了。gulp-bower-files其一插件,可以分析bower.json,把依赖的每个库里的main属性组合起来,成立gulp.src()

gulp.task('vendor', function () {
  gulpBowerFiles()
    .pipe(concat('vendor.js'))
    .pipe(gulp.dest('.'))
})

老是手工gulp js不方便?gulp watch起来。

gulp.task('watch', ['js'], function () {
  gulp.watch('src/**/*.js', ['js'])
})

理所当然,这个都是权宜之计,因为传说中的ES6和Angular
2.0,将搞定这多少个问题。然而往日,不妨试试这么些超简单的法门咯。


[补充]

  1. gulp-bower-files已被main-bower-files取代。
  2. moduleconfig等级是有各样倚重的。比如,要定义route里的controller,就要求该controller非得存在。

相关文章