K_Reverter的网页开发记录

要么不做,要么就当作艺术品来做!

2011年1月15日 #

Jla框架介绍(二) 核心和基本规范

    这一篇将介绍Jla框架的核心,在此之前,先要介绍"Jla"这个名称,全称是"JavaScript Lazy App",这个框架的核心是将一系列代码单元组合起来,在页面上按需加载,也就是通俗提到的"懒载入",这也就是这个名字的由来。
    当我们来仔细审视JavaScript相对于其他语言的特点时,我们会发现,安全性和对懒载入的支持是我们不能忽视的特性,安全性是指用户通常会信任JavaScript脚本的运行,因此运行的平台非常广泛,而懒载入则使得我们在开发之中,可以灵活的控制程序单元从服务端流向客户端的过程,这样,就为使用JavaScript进行大型项目的开发提供了可能。
    在现在,越来越多的桌面应用程序正在改为BS模式,原来的程序可能是几十兆甚至上百兆,这种情况下,如果通过BS模式一次加载所有的功能到页面上,会给客户端带来非常不好的用户体验,对服务器的压力也挺大,而且其中的大部分功能未必用户真正能用得上,因此我们最好是将程序进行分拆,任何功能都是在需要的时候再加载,例如点击按钮之后执行的操作等。
    Jla框架正是为解决这个问题而设计的框架,我们先看看该框架是怎么定义的:
    在Jla框架之中,一个程序由众多的代码单元组成,每个代码单元应该是这样的模式:

 1     Jla.require(["namespace.ClassA","namespace.ClassB"],2,function(ClassA,ClassB)
 2     {
 3         //code of ClassD start
 4         function App()
 5         {
 6         }
 7         App.prototype.onClick=function()
 8         {
 9             Jla.require(["namespace.ClassC"],1,function(ClassC)
10             {
11                 //调用ClassC.完成点击之后执行的操作
12             })
13         }
14         //code of ClassD End
15         Jla.set("namespace.ClassD",App);
16     })

 

 

    从上面的代码单元来看,这个代码单元是定义了一个类,这个类的命名空间是namespace.ClassD,通过Jla.set来向框架之中注册这个命名空间,这个类使用到了两个Jla.require方法,代表这个类在运行时会依赖其他的类。
    当一个类需要调用其他类的时候,要求使用Jla.require模式,该模式有三个参数:
    参数1是一个命名空间数组,代表需要调用哪几个类
    参数2是依赖的类型,有三种类型:
        值1代表应该立即去获取该类,并在获取完成之后执行回调函数,主要用在需要懒载入的情况,例如点击按钮之后执行的函数等
        值2代表的含义和1相同,但是进一步建议在代码发布时应该将这几个类也打包在一起(意味着依赖程度太高,不建议使用动态加载),主要用在一个类必须引用另一个类才能运行的情况下
        值0代表不需要主动去加载该类,但假如该类已经加载或者后面被其他的类引用加载,则执行回调函数,用的比较少,主要用在一些事件绑定过程上。
    参数3是回调函数,在需要的类都加载完成后,会自动执行回调函数,而且会将需要的类列表作为回调函数的参数传递,这样就可以直接使用那些类,而不需要再次执行
    虽然以上的代码非常简单,实际上也就使用了Jla.require和Jla.set两个函数,但这段代码已经完整表达了Jla框架的核心规范,我简单的描述一下这个核心所定义的规范:
    1.不要直接调用一个类,对外部类的引用都应该通过Jla.require来引用,虽然你可能直接通过命名空间或者Jla.get(namespace)调用到那个类,因为这样就破坏了规范,而且如果你调用的时候该类还没有加载完成,就会出现异常;
    2.每个代码单元都应该明确在实现自己的逻辑的过程中需要依赖哪几个类,依赖程度如何,只有对这些能明确下来,才能保证最后应用程序只会载入需要的逻辑单元;
    3.每个类都只应该关心自己实现的逻辑,而不需要关注最终的程序是什么样子的,这样才能保证每一个代码单元的重用性。
    这个框架规范比较简单,仅仅拿着这个框架去开发会遇到一些麻烦,但是实际上这已经是一个完整的开发框架,后面我继续描述的内容比较多,但都是依赖这个框架的应用,并不是对这个框架的补充。

posted @ 2011-01-15 13:09 K_Reverter 阅读(1192) 评论(4) 编辑

Jla框架介绍(一) 导言和发展历程

    不经意间,从事前端开发已经有7年了,慢慢的,我从最开始的写简单的表单验证脚本和滑动效果,过渡到基于OOP的类库开发,然后又经历了长时间的JavaScript模块化开发过程,现在,我开始觉得应该重新整理对JavaScript开发的模式和思路,因此,我会开始写一系列文章来介绍我在JavaScript开发遇到过的问题、解决方法,以及我目前认为比较合理的JavaScript开发新模式。

 

    这些心得都是直接针对我以前遇到的项目的解决方案,因此不见得会对读者带来直接的借鉴意义,因为据说“简单的项目都是一样的,复杂的项目则各有各的复杂”,但是我觉得我遇到的问题应该也是进行大型的JavaScript开发都会遇到的问题,希望能对大家有所帮助,并希望留下你的意见,一起探讨JavaScript开发的问题。
    这一篇是简单的介绍我在JavaScript上的开发经历(有些枯燥,不过对后续内容有帮助),最近,我将自己脚本开发的过程分为四个阶段:
    第一个阶段非常简单,就是进行简单的页面上功能开发,例如表单输入的验证、页面上的元素飞来飞去的效果、在页面上实现的一个时钟,这种也算是JavaScript以前最广泛的用法了,以前大部分的页面和网站开发并不需要太复杂的页面动态功能,或者说,在JS真正流行起来前,页面上稍微复杂的功能都由服务器完成。
    在这个阶段之中,很少用到类,脚本直接写在页面上(实在太大了才会分离成单独的文件),从不对代码进行混淆和压缩处理,甚至当年浏览器的兼容性都很少去考虑,总之一切开发都比较原始和懵懂。

 

    我从这个阶段脱离是一个偶然,这要感谢Google,推出了Google Maps API,当时我看到这个API的时候,当时就震惊了,我都不敢相信居然这不是Flash做的,这让我产生了极大的好奇,我一定要弄明白这个脚本是怎么做的,因此我下载了Google那个庞大的脚本文件进行分析和解读(这应该算是Js脚本开发的优点,虽然Google对脚本做了混淆处理,但是如果有耐心,看懂是没有问题的,而且1.0混淆机制还比较简单)
    当我读完差不多60%的代码之后,我觉得我以前的JS开发完全是井底之蛙,我第一次知道用脚本还可以做下面的事情:
    1.进行类的定义和继承
    2.实现自定义的事件机制,例如地图的移动、缩放的事件
    3.可以对DOM进行完全的、复杂的控制,以前我似乎就只进行过层的移动和隐藏
    4.开发出一个库文件,可以在任意时候调用这个库
    5.将复杂的功能进行拆解为插件保证结构清晰、使用灵活,例如地图之中的控件和标注
    就这样主体+插件的架构和类库的开发成了我在第二阶段的主要工作内容,就在这时,我离开深圳的那个小公司,返回到北京,在灵图负责地图API的开发,当时,灵图是国内第一个开放地图API的公司,感谢灵图,让我得以将这种架构下的开发渐渐深入。
    后来我因为一些原因离开灵图到了腾讯(在腾讯主要是从事简单的PHP开发,脚本方面没有什么特别可说的),后来又离开腾讯到了阿里,当时阿里的地图团队刚刚组建,需要快速开发出一套地图API,当时我遇到了难题:难道要把在灵图的工作再做一遍?这是我无法忍受的,因此我总结了一下以前开发架构的遇到的问题,并重新制订出新的解决方案。
    这也就是第三个阶段的主要思路,我称之为泛插件化(一切都是插件),因为在前面的体系之中,只有相对独立的单元(例如地图上的平移缩放组件)才会被开发成插件,大部分的功能还是在主体里面完成的,这样带来一个问题,就是主体的逻辑比较复杂,代码也比较庞大,非常不利于维护,在需要定制一个不同的主体的时候,需要主体提供配置的方法,时间一长,主体就越来越臃肿,这样,必须将主体进行进一步的拆分。
    因此我想,可不可以将所有的主体的所有功能都通过插件实现呢,假设我建立一个地图的类,除了实现一个插件的添加和卸载机制外,几乎什么功能都没有,然后我顺次给他添加投影控件、图层管理控件、标注管理控件、拖拽支持控件……等一系列控件,这些控件分别为主体添加特定的功能,最终得到和以前的主体一样的对象。
    这样做的好处是程序结构非常清晰,便于维护,而且你可以通过选择某些插件加载或不加载来完全的定制你需要的功能。
    遇到的问题是插件之间的耦合,以前的主体+插件的架构之中,插件之间完全不需要交互,因为每个插件的功能是独立的,都只需要和主体交互就可以了。现在所有功能都由插件来完成,肯定需要支持插件之间的交互,对这个问题,我的思路是这样的:
    1.插件只和主体交互,调用主体的特定的方法
    2.插件可以将自己的一些方法赋给主体,这样其他插件调用主体的方法的时候,实际上操作是由另一插件来完成的
    这种泛插件化的机制因为使程序的逻辑清晰,被我广泛的应用到了一些前端开发的项目之中,后面我又在这个基础上附加了插件按需加载(懒载入的功能)。
    但是这种模式目前也遇到一些问题,在我总结起来主要如下:
    1.因为是插件,所以每个插件开发的时候都按照一个固定的模式,这种模式使得代码重用性低,因为任何时候想使用这个插件,必须实现一个主体类
    2.虽然实现了按需加载,但是必须是每次加载的时候手动的指定去下载哪个模块
    3.各个模块都将方法和事件附加到主体上,模块比较多之后,显得比较乱,不便于管理
    4.每个模块的相互依赖关系不清晰
    因为遇到这些问题,我觉得应该重新思考一个新的模式来进行脚本的开发,这就是我现在正在尝试的模式,这个新的框架应该是包含如下的特性:
    1.原生支持代码的按需加载,不得不说按需加载是JavaScript的重要特性之一,因此,应该要求每个代码单元明确的指明对其他单元的依赖程度,类似于其他语言的import、include和require,但是必须考虑到远程加载的支持,没有被引用的块不会被加载
    2.每个代码块有自己的资源库(图片、CSS等),代码单元可以随时调用资源库的资源,而不用费心去管理具体每张图片部署在什么地方;
    3.提供对每个代码块的配置机制,可以在应用的时候对任意的逻辑进行配置
    4.实现一个类似的上面的提到的插件机制,不过不再对插件的接口和继承做规范性的要求,在插件需要耦合的时候,直接提供目标插件的实例,也就是说每个模块A在初始化的时候告诉主体需要哪几个另外的模块B,C才能完成初始化,主体会在模块B,C都完成后将对应的模块实例直接传递过来,这样A就可以使用B和C的实例完成初始化,这样主体只做实例管理的功能,而不再承担模块交互的任务。
    5.框架核心不包含任何功能,并尽可能简短;
    6。实现一个代码的发布和混淆机制,通过这个机制,可以将上面开发的代码生成为压缩过的静态文件用来对外发布。
    通过以上的设计,我希望最终做到每个代码单元都明确自己的逻辑,简单的引用其他代码单元而不需要掺和到其他逻辑之中,这样,能体现JavaScript按需加载的优点,又能够使开发流程清晰化。
    后面,我会逐步的介绍我对这样一个框架的探索过程,敬请关注,谢谢!

posted @ 2011-01-15 10:45 K_Reverter 阅读(1432) 评论(8) 编辑