`
逐行分析JS源代码
  • 浏览: 87111 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

JS模块化编程总结_待续

阅读更多
一、背景:
    随着的互联网技术的不断发展,浏览器逐渐进化为集大成的CS客户端,页面功能向系统级、软件级靠拢的趋势下,开发团队也需要一些软件工程的方法来开发WEB项目,如测试驱动、面向对象,而模块化编程更是成为一种急需应用的技术。
 
全栈技术新Q群:435485569
    
二、需求:
    为方便文件管理、增加复用,我们需要细化JS文件,每个文件负责一个职能,称之为模块,明确每个文件的职能,当交互功能较复杂时,引用的文件也越加庞大,此时我们就需要模块化管理。
    如我们编写一个模块组件Dialog.js,但其依赖event.js / bootstrap.js / component.js,而event.js又依赖 base.js / core.js / el.js,bootstrap.js依赖 boot.js / under.js / almond.js,同理可能依赖更多的js,传统方法我们用到Dialog.js时实际上需要引用9个js,如下
    
<html>
    <body>
    ...
     <script src="/public/base.js"></script>
     <script src="/public/core.js"></script>
     <script src="/public/el.js"></script>
     <script src="/public/boot.js"></script>
     <script src="/public/under.js"></script>
     <script src="/public/almond.js"></script>
     <script src="/module/event.js"></script>
     <script src="/module/bootstrap.js"></script>
     <script src="/module/component.js"></script>
     <script src="/widget/dialog.js"></script>
    </body>
    </html>
 
    我们将其细分,Dialog所依赖的每个js都负责了某一独立功能,分开便于其它组件复用,也利于学习理解。
    但将这9个js都到html里显示引用,工作量却非常可观,且不能弄错路径及加载顺序,若后续Dialog.js又需要多引用一个js,所有的项目都要手动增加,且这样依次同步加载下来会导致会占用浏览器线程,可能导致假死。
   
    模块化作用:
    模块化的作用正是解决上面提到的两点问题。
    1、实现js文件的异步加载,避免浏览器假死。
    2、管理模块之间的依赖,便于模块的维护
    
    三、模块化实现:
    模块化,就是把一个相对独立的功能,单独成一个文件,可输入指定依赖、输出指定的函数,供外界调用,其它都是内部的。这样即可方便不同的项目重复使用,也不会对其造成额外的影响。而既然要给不同的项目应用,特别像git上的模块是面向全球范围的,必然要形成可遵循的规范,开发者和使用者都有据可寻。
    目前通用javascript规范分为服务端(CommonJS),客户端(AMD / CMD)。
    CommonJS是针对javascript的服务端,一切模块都是通过require来同步加载调用, Nodejs采用的就是这个规范。
    
var module1 = require( 'module1'),
              module2 = require( 'module2' );

    function module3(){

     }
    exports.module3 = module3;
 
    注:通过require加载module1、2,操作后通过exports导致module3。
 
    这里我们主要讲客户端模块
    客户端与服务端的不同在于异步加载,之所以异步是因为CommonJS规则应用在服务端时,文件都是本地硬盘读取,不受限于网络,等待硬盘读取时间很短。而浏览器要考虑网速,若长时间等待会导致浏览器假死。
 
    引用形式如下图
 
    
    以前研究过sea.js某版本的源码,其原理就是将通过模块化加载的js,计算出其路径插入到 html.head里。
     
     四、AMD。
     是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义",
    以require.js为代表,官网http://requirejs.org/ ,其形式主要是
   
 =============main.js===================
     <script src="js/require.js" data-main="js/Dialog"></script>

    ==============Dialog.js=======================
     define( ['event', 'bootstrap', 'component' ], function( event, bootstrap, component ){
          event.doSomthing();
          bootstrap.doSomthing();
           component.doSomthing();
          var Dialog = function(){
              ...
          }
          return {
              Dialog: Dialog
         }
     });
 
     注:require接收两个参数,第一个参数是数组,含需加载的模块,第二个参数是回调,在模块加载成功后执行,且回调中的参数对应模块的加载顺序,这样主程序只需要加载一个JS文件,Dialog.js即可,其自会去加载event.js等文件,event.js再用同样的方式去加载base.js等,使用者无需考虑Dialog加载了多少引用,也无法担心其使用后会增减依赖。
    
     五、CMD:以sea.js为代表,官网 http://seajs.org/docs/,理念为需要时再执行,即依赖就近
     
=============main.js===================
     <script src="js/sea.js"></script>    
  <script>seajs.use("../static/hello/src/main")</script>

    ==============Dialog.js=======================
          define( function( require, exports, module ){
                  var event = require( 'event' );
                  event.doSomthing();
                  var bootstrap = require( 'bootstrap' );
                   bootstrap.doSomthing();
                   var component = require( 'component' );
                  component.doSomthing();
                  var Dialog = function(){
                      ...
                  }                    
         exports.Dialog = Dialog;
         })
 
    注:模块引用本身就在回调里,并且在使用前引用即可,所以sea.js特别的是懒加载,这也就是AMD和CMD之间唯一的区别。实际上,require.js也支持CMD的写法,不过依赖前置是其官方推荐。我最初因为对国产和玉伯的支持敬佩,使用了seajs,近来为了弄清楚AMD,项目全部用了requirejs,虽然网上及seajs官方对两种逻列了一些分别,但使用下来,感觉并无优劣。
 
    六、UMD
    因服务端与客户端对模块化加载方式的不同,就会人想做一个兼容的模块UMD(Universal Module Definition),来解决跨平台的问题。但对于我们开发者来讲实则没有什么意义,也不深入了。
    
    七、require.js详解:
    
require.config({
          baseUrl: 'module/js',     //配置path下的统一目的,以便path中不会分别配置
          path: {                              //配置module路径,以便引用时不用写全路径
              module1: 'module1',
              module2: 'module2',
              module3: 'http://www.site.com/module3'     //若引用的是第三方,可以全部全路径
         },
          shim: {     //对不符合AMD规则的模块引用
              'underscore': {
                   exports: '_'          //配置其原对外接口
              },
              'backbone': {
                   deps: ['underscore', 'jquery'],     //配置其依赖项
                   exports: 'Backbone'
             }
         }
     });

    define( ['module1', 'module2' ], function( module1, module2 ){
          module1.doSomthing();
          module2.doSomthing();
          function module3(){
              ...
         }
          return {
              module3: module3
         }
     });
 
 
    八、require.js时间戳:
    require.js没有找到可配置时间戳,可修改require.js源文件中的load方法 
     
load: function (id, url) {
        url += '?' + timestamp;     
        req.load(context, id, url);     
    },
 
    
 新增 url += '?' + timestamp; 这一处语句,即为url添加timestamp,timestamp可以另外通过配置文件配置。我使用nodejs开发,在服务端的config文件配置 timestamp: '2015091112',将其插入到客户端 ejs文件内
    
 <script>
         var timestamp = '<%= timestamp %>';
     </script>
 
     这样即可在 require.js 文件内调用。
 
    九、require.js合并:
    官网提供了r.js用于该模块化的打包  https://github.com/jrburke/r.js   http://requirejs.org/docs/download.html#rjs
    r.js是将通过require.js引用的模块化文件都合并到一个文件里,以减少文件加载数量。
    首先下载r.js,可以到静态文件根目录,新建build.js用于配置r.js,常见的配置如下
    项目参考 https://github.com/xiaolulu/mynodejs.git
    
({ 
	appDir: './', //项目根目录,给后面的baseUrl做参考;非必要项;默认为与r.js平级目录
	dir: './min', //压缩后的文件的输出目录 
	baseUrl: './', //模块相对目录,与后面的paths配置使用
	modules: [ 
		{ name:'login'},
		{ name: 'register' },
		{ name: 'center' }
	], 
	fileExclusionRegExp: /^(r|build)\.js|.*\.scss$/, //过滤文件不压缩
	optimizeCss: 'standard', //css的标准方式
	optimize: 'uglify', //设置是否压缩;uglify(压缩格式)|none(只合并不压缩)
	removeCombined: true, //设置移除压缩后的文件
	paths: { //设置模块别名,方便引用,压缩后require.js引用的模块路径就在这里定义的,不是require.config里的
		md5: 'core/js/md5',
		validate: 'widget/validate/validate',
		all: 'public/js/all',
		login: 'module/issue/login/login',
		register: 'module/issue/register/register',
		center: 'module/user/center/center'
	}
});
 
 
    执行 node r.js -o build.js
    
    十、almond:
    合并后所有原通过模块化加载的文件都已经在一个文件里了,已经不需要require.js的大部分功能,但因合并后代码里还是有require / define的函数定义,这里命令解析还是要有的,所以就有了almond.js(约15KB),其保留了require.js(约80KB)的子集,但不支持模块化加载,即对已经合并后的模块解析可以使用,减少代码量。
    不过,其理念是好的,但实现方案还待改进,其执行后就会almond.js与前面合并后过的业务JS合并成一个文件,直接用 src来引用,意味着每个页面都需要的 almond.js将无法缓存,所以当业务JS超过五个时,这个方案将没有意义
0
1
分享到:
评论

相关推荐

    C++知识总结(未完待续)

    结构化程序设计,又称为面向过程的编程,主张使用顺序、选择和循环这三种基本结构来组织代码,同时提倡模块化的单入口单出口设计原则。这种设计方法鼓励自顶向下、逐步求精的编程策略,即从整体到细节,逐步完善程序...

    9--[小黑点的旅行(未完待续)].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码

    9--[小黑点的旅行(未完待续)].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码9--[小黑点的旅行(未完待续)].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码9--[小黑点的旅行(未完待续)].zip...

    基于PHP常用字符串的总结(待续)

    本篇文章是对PHP常用的字符串进行了详细的总结分析,需要的朋友参考下

    小黑点的旅行(未完待续)-少儿编程scratch项目源代码文件案例素材.zip

    《小黑点的旅行》是一个针对少儿编程设计的项目,主要使用了Scratch这一图形化编程语言。Scratch是麻省理工学院(MIT)的“终身幼儿园团队”开发的一款面向儿童的免费编程工具,旨在通过游戏化学习的方式,激发孩子们...

    前端经验,遇到的各种问题总结,未完待续

    小白必看;前端一年工作经验,遇到的各种问题总结, 未完待续

    Android应用--简、美音乐播放器原型放送(作者:小巫) - 巫_1曲待续

    Android应用--简、美音乐播放器原型放送(作者:小巫) - 巫_1曲待续 Android应用--简、美音乐播放器原型放送(作者:小巫) - 巫_1曲待续

    大数据Java面试总结(未完待续).docx

    微服务架构的优点在于模块化、可扩展性,但也会带来复杂性,如服务间通信、治理等问题。 **服务管理** 服务管理主要通过RPC(远程过程调用)实现,如Dubbo、gRPC等。负载均衡确保高可用性,容错机制包括超时、重试...

    java精典编程100例 7

    java 精典编程 100 例,待续...... author:朱千平 phone:13522080786 qq:200896066

    C#编程语言详解C#编程语言详解

    C#编程语言是一种由微软公司开发的面向对象的编程语言,主要用于Windows平台的应用程序开发,尤其是在.NET框架上。本文档详细介绍了C#语言的核心概念和特性。 1. 介绍 C#语言的设计目标是简洁、现代和类型安全,...

    C#笔记,待续ing

    C#笔记,北京大学唐大仕老师课件的总结,待续Ing,没什么想说的

    几个shell编程的小例子

    在IT领域,Shell编程是一种非常基础且强大的工具,它允许用户通过命令行接口与操作系统进行交互,执行自动化任务。在给定的“几个shell编程的小例子”中,我们可以看到四个不同的脚本示例,分别涉及了不同的编程概念...

    城市学院5/10编程题库

    下面是对每个题目的详细解释和知识点总结: 1. 编程题:输入三个正整数,判断能否构成三角形,如果能,则判断是普通三角形、等腰三角形还是等边三角形。 知识点:三角形的判定、边长判定、等腰三角形和等边三角形...

    纯js写的数独游戏,保存排名待续

    js写的一个数独游戏,有兴趣的朋友来耍下

    【西门子博图plc编程案例程序大全】PLC案例程序205套(S7-200和SMART+S7-300 400+1200与1500)

    西门子博图plc编程案例程序合计205套,目录如下: 01_S7-200和SMART200 共105套 S7-200 项目案例含注释(35套) S7-200 项目案例无注释(50套) S7-200 SMART项目案例(20套) 02_S7-300 400 项目案例部分有注释(80套) ...

    信息可视化方法总结

    信息可视化方法总结 信息可视化是将复杂的数据信息转换为易于理解和分析的视觉形式,以便更好地理解和分析数据。信息可视化方法可以帮助人们更好地理解和分析数据,发现隐藏的模式和规律,提高数据分析效率和准确性...

    C++课件前半部待续!

    "C++课件前半部待续!"这个标题表明这是一系列关于C++语言的教学材料,主要涵盖了C++的基础部分,并且课程还没有完全结束,后续可能还有更多内容。 描述中提到,这些课件适合初学者,易于理解,适合喜欢通过课件...

    Oracle PL/SQL实战(待续)

    此外,PL/SQL的包(PACKAGE)概念是将相关的过程和函数封装在一起,提供更好的模块化和重用性。包由包规范(PACKAGE HEADER)和包体(PACKAGE BODY)组成,前者声明公共接口,后者实现具体逻辑。通过包,我们可以...

    Shell编程常见面试题(待续)

    在IT行业中,Shell编程是系统管理员和开发人员必备的技能之一,因为它允许高效地自动化日常任务和管理系统。以下是一些常见的Shell编程面试题及其详细解答: 1. **查询空行所在的行号** 使用`awk`命令,通过正则...

    node-red-contrib-f2flowchart:Node-Red功能节点的派生版本,可从Javascript代码生成编程流程图

    功能到流程图是原始“红色节点功能”节点的派生版本,用于从Javascript代码生成编程流程图。 在Node Js v12和Node Red v1.3.0上创建并测试 该节点基于原始的“节点红色功能”节点,并提供生成和下载与“ On Message...

    教育教学资源库系统 系统源码 论文待续

    同时,"系统源码"的提及意味着包含了实际的编程代码,可供学习和参考,而"论文待续"则提示这可能是项目完成后进一步理论总结和分析的组成部分。 【描述】"这是我的毕业设计,欢迎与大家分享。如果你没有资源分了,...

Global site tag (gtag.js) - Google Analytics