js模块并行加载器:MixJS

自己写了一个js模块加载器,所谓的并行其实也不完全是并行的,只是依赖关系模块是并行的。当然我知道现在有很多类似的js框架,而且MixJS也没有做更加全面的浏览器测试,只是跟我的意识写的一个加载器。

项目放在github上面:https://github.com/ksky521/MixJS
算是给2012年的一个总结。

简单说下功能

跟玉伯的Seajs不同,也跟CMD和AMD不同,我使用的是依赖关系明确的声明模块方式,这样减少了扫描代码读取依赖关系的方式,开发者虽然有了一定的束缚,但是总体来说,后期的维护成本,代码效率和实时combo、上线打包都会大大的降低成本。

MixJS介绍

轻量级前端模块化解决方案,提供模块管理、php实时合并、打包工具等方案。可以用于提供给第三方开发者使用的小组件,核心文件可以单独拿出来作为框架core,在此基础上可以开发出一整套的前端框架

MixJS还在开发完善阶段,未作完整兼容性测试,多数代码是出于解决问题的想法而写的,当然也copy了很多牛人的代码,比如cssload回调借鉴了seajs,Deferred来自于jQuery。。。。

。。。。鉴于最近前端圈比较乱,我的小手都开始颤抖,造轮子必然会被喷,我只能说我是根据自己的意识码了这些的代码,据此操作后果自负。。。。

0.2开发完成,现在开发基于0.2模块的开放平台部分代码,主要包括:Deferred(延迟队列)、API(API接口调用)、Widget(小组件)和XDomain(跨域)

模块加载不是单纯的文件加载,需要根据模块规范来写模块哦~

MixJS代码示例

参考github项目readme文件。

用途

关于MixJS的用途,主要解决是模块开发中的管理、加载。

我赞成使用MixJS是:细模块,粗文件。总体来看MixJS适合Widget开发、开放平台开放js开发,也适合作为模块管理器来打造更加强大的前端架构。

不多说了,吹嘘会被喷的,哈哈~

感谢

MixJS也借鉴了不少大牛的代码(嗯,你可以说是抄袭),感谢seajs,jQuery,mass,curl.js等作者。

使用广播事件来实现模块解耦

模块化开发往往最大的问题是解耦,怎么设计一个低耦合的组件呢?这里我用到的方法是时间总线(eventBus)方法,也可以叫做广播事件,模块之间通过发送广播的方式来实现通信,事件发起者只需要派发事件,而不必关心事件是否被接收(订阅)。

广播事件也是自定义事件的一种,不同于自定义事件,广播事件没有绑定的主体,但是都是通过观察者设计模式来写的代码。
大体的javascript实现代码如下:其中包括一些简单方法没有列出,例如$.isUndefined

var _cache = {};
var broadcast = {
    /**
     * 派发
     * @param  {[type]} type 事件类型
     * @param  {[type]} data 回调数据
     * @return {[type]}      [description]
     */
    fire:function(type, data){
        var listeners = _cache[type],len = 0;
        if(!$.isUndefined(listeners)){
            var args = [].slice.call(arguments);
            args = args.length > 2 ? args.splice(2, args.length-1) : [];
            args = [data].concat(args);

            len = listeners.length;
            for(var i = 0; i<len;i++){
                var listener = listeners[i];
                if(listener && listener.callback) {
                    args = args.concat(listener.args);
                    listener.callback.apply(listener.scope, args);
                }
            }
        }
        return this;
    },
    /**
     * 订阅广播事件
     * @param  {[type]}   types     事件类型,支持,分隔符
     * @param  {Function} callback 回调函数
     * @param  {[type]}   scope    回调函数上下文
     * @return {[type]}            this
     */
    subscribe:function(types, callback, scope){
        types = types || [];
        var args = [].slice.call(arguments);

        if($.isString(types)){
            types = types.split(',');
        }
        var len = types.length;
        if(len===0){
            return this;
        }
        args = args.length > 3 ? args.splice(3, args.length-1) : [];
        for(var i = 0;i<len;i++){
            var type = types[i];
            _cache[type] = _cache[type] || [];
            _cache[type].push({callback:callback,scope:scope,args:args});
        }
        return this;
    },
    /**
     * 退订
     * @param  {[type]}   type     [description]
     * @param  {Function} callback 假如传入则移出传入的监控事件,否则移出全部
     * @return {[type]}            [description]
     */
    unsubscribe:function(type, callback, scope){
        var listeners = _cache[type];
        if (!listeners) {
            return this;
        }
        if(callback){
            var len = listeners.length,
                tmp = [];

            for(var i=0; i<len; i++) {
                var listener = listeners[i];
                if(listener.callback == callback && listener.scope == scope) {
                } else {
                    tmp.push(listener);
                }
            }
            listeners = tmp;
        }else{
            listeners.length = 0;
        }
        return this;
    },
    /**
     * 订阅别名
     * @return {[type]} [description]
     */
    on:function(){
        return this.subscribe.apply(this,arguments);
    },
    /**
     * 退订别名
     * @return {[type]} [description]
     */
    un:function(){
        return this.unsubscribe.apply(this,arguments);
    },
    dispatch:function(){
        return this.fire.apply(this,arguments);
    },

    removeAll:function(){
        _cache = {};
        return this;
    }
};

使用方法:

broadcast.fire('event name', json);
broadcast.on('event name', function(data){
    console.log(data);
});