前端模块机制

1. 什么是模块 ?

  模块就是能够完成一定工作的函数,对象,甚至是基本的数据类型

var hello = function () {
    return 'hello';
}
View Code

   

2. 为什么要使用模块

  页面加载js文件一般通过script引入,当项目比较复杂时会出现问题

  a. 解决命名冲突, 虽然命名空间和YUI3中也能解决命名冲突的问题,但是同时也会带来新的问题

  b. 管理文件之间的依赖, 当项目越来越复杂,文件越来越多,人工维护文件之间的依赖容易出问题,难以管理

  c. 多人开发和维护

  d. 灵活,快速,高效,配合webpack等工具可实现页面优化,按需加载

3. 前端模块加载器原理

    a. id即路径原则,比如webpack打包的文件

   b. createElement('script') & appendChild

  c. document.currentScript

  d. 依赖分析

  e. 递归加载

  加载器的实现要注意的问题比较多,比如循环依赖等

4. 现有模块机制

  CMD (sea.js, coolie.js)

  优点

  a. 依赖就近, 延迟执行

  b. 比较容易在node.js中运行

  缺点

  依赖spm打包,模块的加载逻辑偏重

    判断页面是否有cmd 模块加载器

    define.cmd是一个空对象

if (typeof define === 'function ' && define.cmd) {
    // 有Sea.js等 CMD模块加载器在  
}

    使用方式:

define({foo: 'barr'}) // 定义一个对象模块,导出 {foo: 'bar'}

define(id?, deps?, factory) // id表示标识模块,deps表示模块依赖, 两者可以省略

define(function (require, exports, module) {
    // 获取模块接口
    var a  = require('./a')

    // 异步加载模块, 可以加载多个模块,对应回调函数的参数
    require('./b', function (b) {}) 

    // 可以使用exports, return , module.exports 向外提供模块接口
   // exports 是一个对象
    exports.foo = 'bar'
    return {foo: 'bar'};
    module.exports = {foo: 'bar'}
})

  cmd模块加载流程,

    

    1. 首先,通过 use 方法来加载入口模块,并接收一个回调函数, 当模块加载完成, 会调用回调函数,并传入对应的模块。use 方法会 check 模块有没有缓存,如果有,则从缓存中获取模块,如果没有,则创建并加载模块。
    2. 获取到模块后,模块可能还没有 load 完成,所以需要在模块上绑定一个 "complete" 事件,模块加载完成会触发这个事件,这时候才调用回调函数。
    3. 创建一个模块时,id就是模块的地址,通过创建 script 标签的方式异步加载模块的代码(factory),factory 加载完成后,会 check factory 中有没有 require 别的子模块:
        - 如果有,继续加载其子模块,并在子模块上绑定 "complete" 事件,来触发本身 的 "complete" 事件;
        - 如果没有则直接触发本身的 "complete" 事件。
    4. 如果子模块中还有依赖,则会递归这个过程。
    5. 通过事件由里到外的传递,当所有依赖的模块都 complete 的时候,最外层的入口模块才会触发 "complete" 事件,use 方法中的回调函数才会被调用。
   
  seajs加载原理
  
 一个模块文件被浏览器下载下来后,并不会直接运行我们的模块定义代码,而是会首先执行一个define函数,这个函数会取得模块定义的源代码(通过函数的toString()函数来取得源代码),然后利用正则匹配找到依赖的模块(匹配require("dep.js")这样的字符串),然后加载依赖的模块,最后发射一个自定义事件complete,通知当前模块, 模块已经加载完成,此时,当前模块的就会调用与complete事件绑定的回调函数,完成与这个模块相关的任务
  
  1. 通过script引入seajs文件, 配置seajsconfig参数
  2. 加载入口模块 seajs.use('./main')
 
  其实模块加载流程大体上都比较相似

  AMD (require.js,  curl)

    优点

    a. 可以在浏览器环境中异步加载模块

    b. 可以并行加载多个模块

    缺点

    a. 模块定义的语义不顺畅

    b. 不符合通用模块化思维

    它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

 

 

  CommonJs (nodejs)

    优点

    a. 服务器端模块便于重用

    b. npm中有大多数使用模块包

    c. 简单容易使用

    缺点

    a. 同步加载方式不适合在浏览器环境中,

    b. 不能非阻塞的并行加载多个模块

  commjs只是一种规范,而nodejs实现了这种规范

  

  ES6模块

  1. webpack自带实现commonJs, amd规范模块, 但是需要babel处理es6模块, 还可以使用 es6 module transpiler 或者SystemJs转 es6模块

  2. es6模块自动采用严格模式, 模块顶层 this 指向 undefined;; commonjs模块顶层 this指向该模块

  3.  es6模块中引入commonjs模块 和 commonjs模块中引入es6模块时的用法和区别

 

5. 模块加载环境

 6. 模块打包问题

7. 前端模块为什么需要打包

8. 浏览器端同步加载和异步加载的问题?

  在浏览器端,如果通过 require('math') 加载一个math模块,因为模块都是放在服务器端,如果网络或者模块大小的原因等导致模块加载的时间比较长,则后面的代码没法执行;但是在服务器端就不会存在这个问题,因为服务器端的模块都是放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间,

  所以浏览器端的模块只能采取异步加载,不能同步加载, amd

  

 9. amd,cmd,commonjs, es6模块,各个模块环境中模块解析的兼容性问题,

10. 开发时如何选择那种模块机制,从哪些方面考虑

  a. 性能

  b. 

问题:

1. 使用工具压缩模块代码需要注意哪些地方? 

 

 后续可以自行了解

 

参考连接:

前端模块化开发价值: https://github.com/seajs/seajs/issues/547?utm_source=caibaojian.com

cmd模块定义规范: https://github.com/seajs/seajs/issues/242?utm_source=caibaojian.com

cmd模块加载原理:https://www.zhihu.com/question/21157540

spm打包: http://www.jianshu.com/p/a4ecf762f1be

posted @ 2017-03-15 14:31  她在村口等我  阅读(198)  评论(0编辑  收藏  举报