require.js及模块化编程相关概念

github地址:

https://github.com/requirejs/requirejs

好的文章:https://www.jianshu.com/p/8687f539642c

require.js 是一个JavaScript文件和模块加载器,也是模块管理工具

requireJs 作用是什么,优势是什么? 它解决什么难题?

1. 有效防止了命名冲突

2. 声明了不同 JS 文件之间的依赖关系

3. JS代码以模块化的 方式组织。

requireJs 为解决前端代码库的组织难题,它的解决方案是:

模块化组织js文件

异步加载js文件

JavaScript模块化编程

JavaScript模块化编程的目的是为了让开发者 仅需实现核心的业务逻辑,其他的都加载别人写好的模块就行。

但是JavaScript并不是模块化的语言,ES6才正式支持类和模块,之前的版本不支持类,更不用说module.

什么是模块?  

模块的原始写法:

将不同函数及变量简单的放在一起,看作一个模块。

var a = xxx;

function func1(){...}

function func2(){...}

缺点是:污染全局变量,无法保证 不与其他模块发生命名冲突。而且不能清晰的看出模块成员之间关系;

模块的对象写法

将模块定义为一个对象,所有模块成员放在对象里边。

//将属性和操作都封装在对象中

var module = new Object({

_prop:11,

func1:function(){...}

func2:function(){...}

})

//使用时直接调用对象的属性;

module.func1();

确定:暴露了模块成员,内部状态 可以被外部改写。

module._prop = 100;

立即执行函数写法:

IIFE( Immediately-Invoked Function Express) 可以达到不暴露私有成员的目的

var module = (function(){
  var _prop = 0;
  var fn1 = function(){...};
  var fn2 = function(){...};
  return {fn1:fn1, fn2:fn2};
})();

放大模式/ 继承模式 (augmentation).

如果一个模块很大,必须被分成几个部分,或者一个模块需要继承另外一个模块。

var module = (function(mod){
  mod.fn = function(){...};
  return mod;
})(module);

宽放大模式(Loose Augmentation): 放大模式的改进

浏览器环境中 各个模块 通常都是通过网络获取的。采用放大模式,第一个执行的部分 可能使用一个不存在的空对象,

此时需要要使用宽放大模式 

var module = (function(mod){
  mod.fn = function(){...};
  return mod;
})(window.module || {});

如何保证模块的独立性?如何使用全局变量(其他模块)?

独立性是模块的重要特点,模块内部最好不要与程序的其他模块直接交互。为了在模块内部使用全局变量,

必须显示地将其他变量 作为参数输入模块

var module = (function($){
  
})(jQuery);

AMD规范

Js目前没有官方规范,通用的JS 模块规范有2种,CommonJS和AMD

CommonJS

老实说在浏览器环境下,没有模块并不是特别大的问题,毕竟网页的复杂性有限。但是对于服务端编程,

一定要有模块,否则无法编程。

2009年,美国程序员Ryan Dahl创建了NodeJS项目,将JS用于服务端编程。由此标志着JS模块化编程的正式诞生。

NodeJS的模块系统是参照CommonJS规范实现的,在CommonJS中有一个全局方法require(),用于加载模块。

var match = require("math");

match.add(1,2)

由于一个重大的局限,使得CommonJS规范不适用于浏览器环境。问题是对于服务器而言模块都放在本地,可同步加载等待时间只是硬盘读取时间。但是当浏览器中使用服务端的模块时,等待时间取决于网速快慢,长时间的等待会造成浏览器处于“假死”状态。

因此浏览器端的 模块 不能使用“同步加载(synchronous)", 只能采用“异步加载(asynchronous)"方式,

这就是AMD规范诞生的背景。

AMD (Asynchronous Module Definition) 异步模块加载。

所有依赖模块的语句都定义在一个回调函数中,等到加载完成后,回调函数才会执行。

AMD也采用了require()语句加载模块,不同于CommonJS的是,它要求两个参数。

// module参数为一个数组,里面的成员是要加载的模块
// callback参数是模块加载成功后执行的回调函数
require([module], callback)

// math模块与math.add()加载不是同步的,浏览器不会发生假死,因此AMD比较适合浏览器环境。
require(["math"], function(math){
  math.add(1, 2);
});

RequireJS

加载资源文件

<script src="https://cdn.bootcss.com/require.js/2.3.5/require.js"></script>

在引入require.js文件之后,整个windows 对象就有 require()方法。可以通过require()方法来加载其他JS文件。

RequireJS的入口是 引入时指定的data-main属性,在require.js引入后,会自动执行指向data-main属性所指定的入口文件。

由于引入requireJS本身可能会造成页面失去响应,解决的方式可将其放在网页底部加载。或使用延迟加载。

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

主模块:

data-main加载的是主模块

baseUrl 可通过 requirejs.config手动设置,若没有显示指定config及data-main,则默认的baseUrl为包含requireJS的

那个html页面所属的目录。

$ vim js/main.js
/**
 * RequireJS全局配置文件
 */
requirejs.config({
    //设置项目路径,项目会以baseUrl作为相对路径去查找模块文件
    baseUrl:"./js",
    //预加载JS文件的配置项,默认可不用添加.js后缀
    paths:{
        //RequireJS默认假定所有的依赖资源都是JS脚本,因此无需再module ID上再加上js后缀。
        jquery:"../scripts/jquery-3.3.1"
    }
});

正常情况下,主模块是依赖其他模块的,此时要使用AMD规范定义的require()函数。

require([module], function(module){...});

/**
 * RequireJS全局配置文件
 */
require.config({
    //设置项目路径,项目会以baseUrl作为相对路径去查找模块文件
    baseUrl:"./js",
    //预加载JS文件的配置项,默认可不用添加.js后缀
    paths:{
        //RequireJS默认假定所有的依赖资源都是JS脚本,因此无需再module ID上再加上js后缀。
        jquery:"https://cdn.bootcss.com/jquery/3.3.1/jquery",
        bootstrap:"https://cdn.bootcss.com/bootstrap/4.1.1/js/bootstrap"
    }
});

require(['jquery', 'bootstrap'],function($, undefined){

});

RequireJS要求每个模块是一个单独的JS文件,如果多加载几个模块会发出多次HTTP请求,

实际上,虽然部分的函数库符合AMD规范,但更多的库并不符合。

RequireJS 如何加载非规范的模块呢?

在使用require()之前,需在require.config()函数中定义非规范模块的特征。

require.config()接收一个配置对象,此对象除了paths属性之外,还有一个shim属性,专门用来配置不兼容的模块。每个模块需要定义exports值即输出的变量名,表明这个模块外部调用名称。其次deps数组属性表明该模块的依赖性。

RequireJS源码解析

requireJS工作流程

  • 载入模块
  • 通过模块名解析出模块信息并计算出URL
  • 通过创建script的形式将模块加载到页面
  • 判断被加载脚本若存在依赖则加载,若不存在则直接执行factory()
  • 等待所有脚本都加载完毕后执行回调函数

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章