浅谈前端模块化

  • 模块化编程
  • CommonJS
  • AMD(Asynchronous Module Definition)规范
  • requireJS与seaJS
  • requireJs 以及 seaJs 的区别

模块化编程:

@为了更好的开展话题,首先需了解什么是前端模块化

模块的由来:

其实模块化的诞生不难理解,我们知道因为随着网站逐渐的发展,嵌入网页的Javascript代码越来越庞大,而网页越来越像桌面程序,需要一个团队去分工协作,进行管理和测试等等,为了更好的管理网页的业务逻辑,产生了模块化编程的理念。

模块的定义:

模块就是实现特定功能的相互独立的一组方法。

模块的意义:

因为有了模块,我们能更好的管理网页的业务逻辑,以及按照自己的需求去使用各种模块,并且可以让每个开发者都能设计自己想要的模块以及去使用别人的模块代码。 @有了模块的概念,但为了让大家能方便的加载各种模块,因此需要一套编写模块的规范,而目前通行的Javascript的模板规范共有两种:CommonJS 和 AMD

CommonJS

CommonJS的历史渊源: nodejs项目的诞生,将javascript语言用于服务器编程。由于服务器端开发十分复杂,需要与OS以及其他应用程序互动,模块化的理念对服务器端开发是必需的。而nodejs的模块系统,就是参照CommonJS规范实现的

@因此我理解CommonJS即为服务器端模块的规范。 CommonJS的规范: 根据CommonJS规范,一个单独的文件就是一个模块。加载模块使用require方法,该方法读取一个文件并执行,最后返回文件内部的exports对象。下面就是一个简单的模块文件example.js

console.log("example.js");
exports.message = "hi";
exports.say = function (){
    console.log("hello");
};

使用require方法,加载example.js. 这时变量example就对应模块中的exports对象

var example = require('./example.js');

AMD规范

AMD的历史渊源:

CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD规范则是非同步加载模块,允许指定回调函数。由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。

@因此我理解AMD即为能在客户端环境,并且能兼容服务器端模块的一种模块规范。

AMD的模块定义:

AMD规范使用define方法定义模块,下面是一个例子:

define(['package/lib'], function(lib){
    function foo(){
        lib.log('hello world');
    }
    return{
        foo: foo
    };
});

Define第一个参数表达依赖的模块数组,第二个为加载完依赖的模块数组后,模块执行的函数

AMD的模块加载定义:跟CommonJS 一样,AMD也采用require()语句来加载模块,但是与CommonJS不同的是,它要求有两个参数:

require([module], callback);

第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。AMD形式,就是下面这样:

require(['package/moduleA'], function(moduleA){
    moduleA.add(2, 3);
});

modleA.add()与moduleA模块加载不是同步的,十分适合浏览器的环境

AMD优缺:

AMD 运行时核心思想是「Early Executing」,也就是提前执行依赖 AMD 的这个特性有好有坏:   首先,尽早执行依赖可以尽早发现错误。上面的代码中,假如 a 模块中抛异常,那么 main.js 在调用 factory 方法之前一定会收到错误,factory 不会执行;如果按需执行依赖,结果是:   1、没有进入使用 a 模块的分支时,不会发生错误;   2、出错时,main.js 的 factory 方法很可能执行了一半。      另外,尽早执行依赖通常可以带来更好的用户体验,也容易产生浪费。例如模块 a 依赖了另外一个需要异步加载数据的模块 b,尽早执行 b 可以让等待时间更短,同时如果 b 最后没被用到,带宽和内存开销就浪费了;这种场景下,按需执行依赖可以避免浪费,但是带来更长的等待时间。    引用AMD的Javscript库: 目前,主要有两个Javascript库实现了AMD规范:require.js和curl.js

RequireJS与SeaJS

@根据诞生的时间,先有了Requirejs,然后再诞生了SeaJS。但其实requirejs 和 seajs其实都是模块加载器,只是遵循的模块规范不同,加载机制有所不同。

@在讲解之前,我先说明下模块加载器出现之前存在的两个问题:

  • 最早的时候,所有Javascript代码都写在一个文件里面,只要加载这一个文件就够了。后来,由于代码越来越多,一个文件很难管理并进行维护,必须分成多个文件,依次加载。而一次加载多个js文件有很大的弊端---加载的时候,浏览器会停止网页的渲染,加载文件越多,而网页失去响应的时间就会越长。
  • 由于出现了模块的定义,许多js文件之间存在着依赖关系,因此必须严格保证加载的顺序(即依赖性最大的一定要放到最后加载)

由此可以看出模块加载器的作用,主要是为了解决两个问题: 实现js文件的异步加载,避免网页失去响应 管理模块之间的依赖性,便于代码的编写和维护

RequireJS 与 SeaJS 的异同:

@异同摘录知乎大神的讲法,感觉比较具体和准确 相同之处:   RequireJS 和 SeaJS 都是模块加载器,倡导的是一种模块化开发理念,核心价值是让 JavaScript的模块化开发变得更简单自然。 不同之处:

  • 定位有差异。RequireJS 想成为浏览器端的模块加载器,同时也想成为 Rhino / Node 等环境的模块加载器。SeaJS 则专注于 Web 浏览器端,同时通过 Node 扩展的方式可以很方便跑在 Node 服务器端。
  • 遵循的规范不同。RequireJS 遵循的是 AMD(异步模块定义)规范,SeaJS 遵循的是 CMD (通用模块定义)规范。规范的不同,导致了两者 API 的不同。SeaJS 更简洁优雅,更贴近 CommonJS Modules/1.1 和 Node Modules 规范。
  • 社区理念有差异。RequireJS 在尝试让第三方类库修改自身来支持 RequireJS,目前只有少数社区采纳。SeaJS 不强推,采用自主封装的方式来“海纳百川”,目前已有较成熟的封装策略。
  • 代码质量有差异。RequireJS 是没有明显的 bug,SeaJS 是明显没有 bug。
  • 对调试等的支持有差异。SeaJS 通过插件,可以实现 Fiddler 中自动映射的功能,还可以实现自动 combo 等功能,非常方便。RequireJS 无这方面的支持。

总结:

前端模块化的诞生,大大促进我们前端的发展。前端模块化是web前端需掌握的基础知识之一。

参考:

http://www.douban.com/note/283566440/

http://wiki.commonjs.org/wiki/Modules/1.1

http://seajs.org/docs/

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序猿DD

Spring Cloud构建微服务架构:消息驱动的微服务(核心概念)【Dalston版】

通过《Spring Cloud构建微服务架构:消息驱动的微服务(入门)》一文,相信大家对Spring Cloud Stream的工作模式已经有了一些基础概念,比...

3945
来自专栏架构说

CPU核数和线程 (池)数量的关系(概念理解)

目前手机配置: 支持HUAWEI Mate 8非凡表现的, 是拥有强大性能的华为麒麟950芯片。 此芯片为八核4*Cortex A72 ...

3596
来自专栏JMCui

Spring消息之STOMP

2194
来自专栏linux驱动个人学习

linux交换空间

swap空间有两种形式:一是交换分区,二是交换文件。总之对它的读写都是磁盘操作。 linux内存通过 virtual memory 虚拟内存来管理整个内存, 虚...

3497
来自专栏ThoughtWorks

使用Enzyme测试React(Native)组件|洞见

组件化与UI测试 在组件化出现之前,我们不谈UI的单元测试,哪怕是对于UI页面进行测试都是一件非常困难的事情。其实组件化并不完全是为了复用,很多情况下也恰恰是为...

2814
来自专栏java一日一条

陌陌通讯协议的学习

陌陌发展刚开始由于规模小,30-40W的连接数(包括Android后台长连接用户),也使用XMPP;由于XMPP的缺点:流量大(基于XML),不可靠(为传统固定...

472
来自专栏架构师之路

主从DB与cache一致性

本文主要讨论这么几个问题: (1)数据库主从延时为何会导致缓存数据不一致 (2)优化思路与方案 一、需求缘起 上一篇《缓存架构设计细节二三事》中有一个小优化点,...

40912
来自专栏Java技术

Apache Kafka:下一代分布式消息系统

Apache Kafka是分布式发布-订阅消息系统。它最初由LinkedIn公司开发,之后成为Apache项目的一部分。Kafka是一种快速、可扩展的、设计内在...

481
来自专栏Java架构沉思录

五分钟入门消息中间件

众所周知,消息中间件是大型分布式系统中不可或缺的重要组件。它使用简单,却解决了不少难题,比如异步处理,系统耦合,流量削锋,分布式事务管理等。实现了一个高性能,高...

763
来自专栏Java工程师日常干货

ActiveMQ从入门到精通(一)JMSActiveMQ QuickStartWrite Code 4 ActiveMQ在说说Session关于消息的priority/ttl/deliveryMode

这是关于消息中间件ActiveMQ的一个系列专题文章,将涵盖JMS、ActiveMQ的初步入门及API详细使用、两种经典的消息模式(PTP and Pub/Su...

732

扫码关注云+社区