前端模块化

简介

JS模块化主要这几种AMD CMD CommonJS
ES6 Module跟Commjs非常像。

为什么需要模块化?

最早的时候,所有Javascript代码都写在一个文件里面,只要加载这一个文件就够了。后来,代码越来越多,一个文件不够了,必须分成多个文件,依次加载。下面的网页代码,相信很多人都见过。

<script src="1.js"></script>
<script src="2.js"></script>
<script src="3.js"></script>
<script src="4.js"></script>
<script src="5.js"></script>
<script src="6.js"></script>

这种写法问题:

  1. 首先,加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间会越长
  2. JS文件之间存在依赖关系,因此必须严格保证加载顺序,代码编写和维护都会变得困难。
  3. 命名空间,两个包(模块)之间的命名不冲突。一个模块是一个独立的命名空间

AMD

异步模块定义。 浏览器端模块化开发规范
异步加载模块,模块的加载不影响他后面语句的运行。所有依赖这个模块的语句都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行
回调的形式,异步的形式来运行~!

require.js的加载

一般加载这个文件会像下面这样加载。

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

async属性表示这个文件需要异步加载避免网页失去响应。defer是延迟到最后加载。 那么它就可以移到页面的底部。这会让你的页面加载的快一点。

data-main指定程序的主模块

模块的写法

对于requirejs来说,我们当前这个模块用到什么模块就要写依赖模块,提前加载执行,等待回调。

// main.js
  require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
    // some code here
  });

require()函数接受两个参数。第一个参数是一个数组,表示所依赖的模块,上例就是[‘moduleA’, ‘moduleB’, ‘moduleC’],即主模块依赖这三个模块;第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块。

模块的加载

// Place third party dependencies in the lib folder
// 入口文件
// Configure loading modules from the lib directory,
// Some lib from CDN!!!!!
// except 'app' ones, 
//only use shim config for non-AMD scripts
//Here we config bootstrap.min.js, it depends jquery,so we should write deps:['jquery']
//exports: the name you use. We introduce the bootstrap using CDN, then config it using shim!

require.config({
//直接改变基目录
    baseUrl:"./js/common",
    paths:{
        "app":"../app",
        "jquery":"//libs.baidu.com/jquery/2.0.0/jquery.min",
        "bootstrap":"//libs.baidu.com/bootstrap/3.0.3/js/bootstrap.min"
    },
    shim: {
        'bootstrap': {
            //These script dependencies should be loaded before loading
            //bootstrap.min.js
            deps: [ 'jquery'],
            //Once loaded, use the global 'bootstrap' as the
            //module value.
            exports: 'bootstrap'
        },
    }
});

require.config用于加载lib中的库,一些库是来自CDN,我们都可以在paths中定义。
SHIM
shim是用来加载non-AMD的脚本,
1)export定义你的输出的模块名。
2) deps数组,表明该模块的依赖性

对于优化加载外部库文件
require.js要求,每个模块是一个单独的js文件。这样的话,如果加载多个模块,就会发出多次HTTP请求,会影响网页的加载速度。因此,require.js提供了OPTIMIZER这样一个优化工具,当模块部署完毕以后,可以用这个工具将多个模块合并在一个文件中,减少HTTP请求数。

AMD写法

定义

 // math.js
define(function (){
    var add = function (x,y){
      return x+y;
    };
    return {
      add: add
    };
});

加载

// main.js
  require(['math'], function (math){
    alert(math.add(1,1));
  });

AMD CMD 规范的明显区别

  1. AMD推崇依赖前置,定义模块的时候就要声明其依赖的模块
    CMD推崇就近依赖,用来某个模块的时候再去require

  2. 加载模块都是异步,同样是异步加载AMD加载模块完之后就会执行该模块,所有模块都加载执行完后会进入require的回调函数,执行主逻辑。
    CMD加载完某个依赖模块后并不执行,只是下载,所有依赖模块加载完成后进入主逻辑,遇到require语句才执行对应的模块。所以这样执行顺序和书写顺序是一样的。

模块化的基础原理

IIFE(Immediately Invoked Function Expression)和 闭包

//立即执行函数可以隐藏细节。 
var myModule=(function(){
    var var1=1;
    var var2=2;
    function fn1(){}
    function fn2(){}
    return {
        fn1:fn1,
        fn2:fn2
    };
})(); //立即执行

这样在模块外部无法修改我们没有暴露出来的变量,函数。
这是模块化的基础。
暴露的函数fn1 fn2 可以修改,如 myModule.fn1;
var1 var2 不能修改,我们只能间接访问。

独立性

独立性是模块重要特点,模块内部最好不与程序的其他部分直接交互。
为了在模块内部调用全局变量,必须显示地将其他变量输入模块。

CommonJS
A 定义模块
根据CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说在这个模块内部定义的变量无法被其他模块读取,除非定义为global对象的属性。
B模块输出
模块只有一个出口,module.exports 对象,我们需要把模块希望输出的内容放入该对象。
前面都跟requirejs类似。
C加载模块
加载模块使用require方法,该方法读取一个文件并执行,返回文件内部的module.exports对象。
require是同步的,模块系统需要同步读取模块文件的内容,并执行得到模块的接口。 就是说模块文件必须一个接一个调用require读取。 如果require加载时间很长,整个应用就会停下!

困境
传统CommonJS模块在浏览器环境下无法正常加载,因为脚本标签会阻塞浏览器线程。

总结

前端模块化不等于JavaScript模块化
前端开发 需要 JavaScript CSS Template互相组织。 requireJS 模块化方案并没有根本上解决模块化问题。
前端模块化不等于JavaScript模块化,如果一个功能只有JavaScript实现了模块化,CSS和Template还是处于原始状态,那我们在调用这个功能的时候并不能完全通过模块化的方式,这样的模块化是不完整的!

真正需要的是把JavaScript CSS Template同时考虑进去的模块化方案!!!而不仅仅是JS模块化—-React!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值