JavaScript模块化之使用requireJS按需加载


Posted in Javascript onApril 12, 2017

模块加载器的概念可能稍微接触过前端开发的童鞋都不会陌生,通过模块加载器可以有效的解决这些问题:

  1. JS文件的依赖关系。
  2. 通过异步加载优化script标签引起的阻塞问题
  3. 可以简单的以文件为单位将功能模块化并实现复用

主流的JS模块加载器有requireJS,SeaJS等,加载器之间可能会因为遵循的规范不同有微妙的差别,从纯用户的角度出发,之所以选requireJS而不是SeaJS主要是因为:

功能实现上两者相差无几,没有明显的性能差异或重大问题。

文档丰富程度上,requireJS远远好于SeaJS,就拿最简单的加载jQuery和jQuery插件这回事,虽然两者的实现方法相差无几,但requireJS就有可以直接拿来用的Demo,SeaJS还要读文档自己慢慢折腾。一些问题的解决上,requireJS为关键词也更容易找到答案。

requireJS 加载jQuery + jQuery插件

可能对于一般Web App来说,引入jQuery及相关插件的概率是最大的,requireJS也亲切的给出了相应的解决方案及动态加载jQuery及插件的文档及实例代码。

在最新的jQuery1.9.X中,jQuery已经在最后直接将自己注册为一个AMD模块,即是说可以直接被requireJS作为模块加载。如果是加载旧版的jQuery有两种方法:

1. 让jQuery先于requireJS加载

2. 对jQuery代码稍做一点处理,在jQuery代码包裹一句:

define(["jquery"], function($) { 
  // $ is guaranteed to be jQuery now */ 
});

requireJS的示例中,直接将requireJS与jQuery合并为一个文件,如果是采用jQuery作为核心库的话推荐这种做法。

同样对于jQuery插件来说也有两种方法

1. 在插件外包裹代码

define(["jquery"], function($){ 
   // Put here the plugin code. 
});

2. 在使用reuqireJS代码加载前注册插件(比如在main.js)中

requirejs.config({ 
  "shim": { 
    "jquery-cookie" : ["jquery"] 
  } 
});

requireJS加载第三方类库

在实例的App中还用到了jQuery以外的第三方类库,如果类库不是一个标准的AMD模块而又不想更改这些类库的代码,同样需要提前进行定义:

require.config({ 
   paths: { 
      'underscore': 'vendor/underscore' 
   }, 
   shim: { 
     underscore: { 
       exports: '_' 
     } 
   } 
});

CSS文件的模块化处理

在requireJS中,模块的概念仅限于JS文件,如果需要加载图片、JSON等非JS文件,requireJS实现了一系列加载插件。

但是遗憾的是requireJS官方没有对CSS进行模块化处理,而我们在实际项目中却往往能遇到一些场景,比如一个轮播的图片展示栏,比如高级编辑器等等。几乎所有的富UI组件都会由JS与CSS两部分构成,而CSS之间也存在着模块的概念以及依赖关系。

为了更好的与requireJS整合,这里采用require-css来解决CSS的模块化与依赖问题。

require-css是一个requireJS插件,下载后将css.js与normalize.js放于main.js同级即可默认被加载,比如在我们的项目中需要加载jQuery Mobile的css文件,那么可以直接这样调用:

require(['jquery', 'css!../css/jquery.mobile-1.3.0.min.css'], function($) { 
});

不过由于这个CSS本质上是属于jQuery Mobile模块的一部分,更好的做法是将这个CSS文件的定义放在jQuery Mobile的依赖关系中,最终我们的requireJS定义部分为:

require.config({ 
   paths: { 
      'jquerymobile': 'vendor/jquery.mobile-1.3.0', 
      'jstorage' : 'vendor/jstorage', 
      'underscore': 'vendor/underscore' 
   }, 
   shim: { 
     jquerymobile : { 
      deps: [ 
        'css!../css/jquery.mobile-1.3.0.min.css' 
      ] 
     }, 
     underscore: { 
       exports: '_' 
     } 
   } 
});

在使用模块时,只需要:

require(['jquery', 'underscore', 'jquerymobile', 'jstorage'], function($, _) { 
});

jQuery Mobile的CSS文件就会被自动加载,这样CSS与JS就被整合为一个模块了。同理其他有复杂依赖关系的模块也可以做类似处理,requireJS会解决依赖关系的逻辑。

数据源的加载与等待

Web App一般都会动态加载后端的数据,数据格式一般可以是JSON、JSONP也可以直接是一个JS变量。这里以JS变量为例:

var restaurants = [ 
  { 
    "name": "KFC" 
  }, 
  { 
    "name": "7-11" 
  }, 
  { 
    "name": "成都小吃" 
  } 
]

载入这段数据:

$.getScript('data/restaurants.json', function(e){ 
  var data = window.restaurants; 
  alert(data[0].name); //KFC 
});

单一的数据源确实很简单,但是往往一个应用中会有多个数据源,比如在这个实例App中UI就需要载入用户信息、餐厅信息、订餐信息三种数据后才能工作。如果仅仅靠多层嵌套回调函数的话,可能代码的耦合就非常重了。

为了解决多个数据加载的问题,我习惯的解决方法是构造一个dataReady事件响应机制。

var foodOrder = { 
 
  //数据载入后要执行的函数暂存在这里 
  dataReadyFunc : [] 
 
  //数据源URL及载入状态 
  , dataSource : [ 
    { url : 'data/restaurants.json', ready : false, data : null }, 
    { url : 'data/users.json', ready : false, data : null }, 
    { url : 'data/foods.json', ready : false, data : null } 
  ] 
 
  //检查数据源是否全部载入完毕 
  , isReady : function(){ 
    var isReady = true; 
    for(var key in this.dataSource){ 
      if(this.dataSource[key].ready !== true){ 
        isReady = false; 
      } 
    } 
    return isReady; 
  } 
 
  //数据源全部加载完毕,则逐一运行dataReadyFunc中存放的函数 
  , callReady : function(){ 
    if(true === this.isReady()){ 
      for(var key in this.dataReadyFunc){ 
        this.dataReadyFunc[key](); 
      } 
    } 
  } 
 
  //供外部调用,会将外部输入的函数暂存在dataReadyFunc中 
  , dataReady : function(func){ 
    if (typeof func !== 'function') { 
      return false; 
    } 
    this.dataReadyFunc.push(func); 
  } 
 
  , init : function(){ 
    var self = this; 
    var _initElement = function(key, url){ 
      $.getScript(url, function(e){ 
        //每次载入数据后,将数据存放于dataSource中,将ready状态置为true,并调用callReady 
        self.dataSource[key].data = window[key]; 
        self.dataSource[key].ready = true; 
        self.callReady(); 
      }); 
    } 
    for(var key in this.dataSource){ 
      _initElement(key, this.dataSource[key].url); 
    } 
  } 
}

用法为:

foodOrder.dataReady(function(){ 
  alert(1);   
}); 
foodOrder.init();

dataReady内的alert将会在所有数据载入完毕后开始执行。

这段处理的逻辑并不复杂,将所有要执行的方法通过dataReady暂存起来,等待数据全部加载完毕后再执行,更加复杂的场景此方法仍然通用。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 在网页中的运用(asp.net)
Nov 23 Javascript
JS Replace 全部替换字符的用法小结
Dec 24 Javascript
轻松学习jQuery插件EasyUI EasyUI创建树形菜单
Nov 30 Javascript
JavaScript iframe数据共享接口实现方法
Jan 06 Javascript
Angularjs中UI Router全攻略
Jan 29 Javascript
老生常谈js-react组件生命周期
May 02 Javascript
微信小程序checkbox组件使用详解
Jan 31 Javascript
JS添加或删除HTML dom元素的方法实例分析
Mar 05 Javascript
Javascript 对象(object)合并操作实例分析
Jul 30 Javascript
vue+vant使用图片预览功能ImagePreview的问题解决
Apr 10 Javascript
AutoJs实现刷宝短视频的思路详解
May 22 Javascript
在react项目中使用antd的form组件,动态设置input框的值
Oct 24 Javascript
使用jQuery和ajax代替iframe的方法(详解)
Apr 12 #jQuery
微信小程序 仿美团分类菜单 swiper分类菜单
Apr 12 #Javascript
jQuery用noConflict代替$的实现方法
Apr 12 #jQuery
jQuery判断邮箱格式对错实例代码讲解
Apr 12 #jQuery
微信小程序 引入es6 promise
Apr 12 #Javascript
JavaScript队列的应用实例详解【经典数据结构】
Apr 12 #Javascript
Vue 实用分页paging实例代码
Apr 12 #Javascript
You might like
PHPMyadmin 配置文件详解(配置)
2009/12/03 PHP
php导出word文档与excel电子表格的简单示例代码
2014/03/08 PHP
php版交通银行网银支付接口开发入门教程
2016/09/26 PHP
php实现的生成迷宫与迷宫寻址算法完整实例
2017/11/06 PHP
jQuery 学习第五课 Ajax 使用说明
2010/05/17 Javascript
Web 前端设计模式--Dom重构 提高显示性能
2010/10/22 Javascript
juqery 学习之四 筛选过滤
2010/11/30 Javascript
javascript使用中为什么10..toString()正常而10.toString()出错呢
2013/01/11 Javascript
当鼠标滑过文本框自动选中输入框内容的JS代码分享
2013/11/26 Javascript
jquery选择器大全 全面详解jquery选择器
2014/03/06 Javascript
js判断字符长度及中英文数字等
2014/03/19 Javascript
原生javascript+css3编写的3D魔方动画旋扭特效
2016/03/14 Javascript
Nodejs Stream 数据流使用手册
2016/04/17 NodeJs
纯JS实现弹性导航条效果
2017/03/06 Javascript
Vue.js手风琴菜单组件开发实例
2017/05/16 Javascript
解决ionic和angular上拉加载的问题
2017/08/03 Javascript
Js中将Long转换成日期格式的实现方法
2018/06/05 Javascript
JS如何监听div的resize事件详解
2020/12/03 Javascript
Python实现的简单发送邮件脚本分享
2014/11/07 Python
Python基于列表模拟堆栈和队列功能示例
2018/01/05 Python
python中使用zip函数出现错误的原因
2018/09/28 Python
python 将有序数组转换为二叉树的方法
2019/03/26 Python
Python学习笔记之抓取某只基金历史净值数据实战案例
2019/06/03 Python
Pytorch 图像变换函数集合小结
2021/02/01 Python
中国第一家杂志折扣订阅网:杂志铺
2016/08/30 全球购物
马来西亚最大的电器网站:Senheng
2017/10/13 全球购物
欧克利英国官网:Oakley英国
2019/08/24 全球购物
美国购买舞会礼服网站:Couture Candy
2019/12/29 全球购物
广告学专业推荐信范文
2013/11/23 职场文书
大三学生入党思想汇报
2014/01/02 职场文书
市场安全管理制度
2014/01/26 职场文书
保护校园环境倡议书
2015/04/28 职场文书
公司欠款证明
2015/06/24 职场文书
2016春季幼儿园小班开学寄语
2015/12/03 职场文书
Java反应式框架Reactor中的Mono和Flux
2021/07/25 Java/Android
未发现nvidia显卡怎么办?Win11系统中未检测到nvidia显卡解决教程
2022/04/08 数码科技