Chinaunix首页 | 论坛 | 博客
  • 博客访问: 477199
  • 博文数量: 55
  • 博客积分: 1867
  • 博客等级: 上尉
  • 技术积分: 587
  • 用 户 组: 普通用户
  • 注册时间: 2006-12-29 01:33
文章分类

全部博文(55)

文章存档

2013年(1)

2012年(2)

2011年(16)

2010年(11)

2009年(5)

2008年(10)

2007年(8)

2006年(2)

分类:

2011-01-28 14:12:02

  在前面的文章《JavaScript名称空间及动态加载》有了一个按java包结构管理javascript代码的基本思想,但里面给出的代码说实在的,比较糙。经过一段时间的试用和调整,做了一些改进。其中的改进的思想是:

1)javascript代码组织

javascript组织在jsvm下,jsvm下有两个子目录classes和lib, classes用于存放框架的类代码,和应用的类代码,框架的类定义在classes/js/下,将会有js/lang, js/net, js/awt, js/util等,含义基本上等同于java的rt包。而应用的类可以定义在classes/com下。lib目录用于放第三方的库文件,比如jQuery等。在jsvm下同时还有一个jsre.js作为框架的启动代码。

2)框架加载方式

<script id="j$vm" type="text/javascript" src="../../jsvm/jsre.js"
         classpath="lib/jquery-1.4.2.min.js;lib/swfobject.js"></script>


在script标签上加上id="j$vm",以及添加一个属性classpath用于自动加载其它包。

3)优化了package和import函数

下面是框架的启动代码:

window.J$VM = new function (){
    var j$vm_home, j$vm_classpath, System;

    this.modules = {};
    
    /**
     * Declare a package
     */

    this.$package = function(packageName){
        if(this.modules[packageName] != undefined) return;

        var names = packageName.split(".");
        var parent = window, pName = [];
        for ( var i = 0, len = names.length; i < len; i++) {
            var name = names[i];
            if (parent[name] === undefined) {
                parent[name] = {};
            }
            pName.push(name);
            parent = parent[name];
        }
        this.modules[pName.join(".")] = parent;
    };

    var _check = function(className){
        if(J$VM.modules[className] != undefined) return true;

        var names = className.split(".");
        var parent = window, pName = [];
        for ( var i = 0, len = names.length; i < len; i++) {
            var name = names[i];
            if (parent[name] === undefined) {
                return false;
            }
            pName.push(name);
            parent = parent[name];
        }

        J$VM.modules[pName.join(".")] = parent;
        return true;
    };
    
    /**
     * Imports a js class dynamically
     */

    this.$import = function(className){
        if(_check(className)) return;

        var buf = [];
        buf.push(j$vm_home);
        buf.push("/classes");

        var names = className.split(".");
        for ( var i = 0, len = names.length; i < len; i++) {
            buf.push("/");
            buf.push(names[i]);
        }
        buf.push(".js");
        var filePath = buf.join('');

        if(this.$load(filePath, false)){
            this.modules[className] = filePath;
        }else{
            if(typeof System != "undefined"){
                System.err.println("Can't load "+className+" from "+filePath);
            }
        }
    };
    
    /**
     * Return the class with specified class name
     */

    this.$class = function(className){
        if(typeof this.modules[className] != "undefined"){
            return this.modules[className];
        }

        var names = className.split(".");
        var parent = window, pName = [];
        for ( var i = 0, len = names.length; i < len; i++) {
            var name = names[i];
            if (parent[name] === undefined) {
                return undefined;
            }
            pName.push(name);
            parent = parent[name];
        }
        this.modules[pName.join(".")] = parent;
        return parent;
    };
    
    /**
     * Return a XHR wrapper
     */

    this.$http = function(){
        return new js.net.HttpURLConnection();
    };
    
    /**
     * Load a javascript file dynamically
     */

    this.$load = function(filePath, async, callback){
        var script = document.createElement("script");
        script.type = "text/javascript";
        var head = document.getElementsByTagName("head")[0];
        if(async){
            if(J$VM.ie){
                script.onreadystatechange = function(){
                    if(this.readyState == "loaded"){
                        if(callback) callback();
                        this.onreadystatechange = null;
                        this.parentNode.removeChild(this);
                    }
                };
            }else{
                script.onload = function(){
                    if(typeof callback == "function") callback();
                    script.onload = null;
                    head.removeChild(script);
                };
            }
            script.src = filePath;
            head.appendChild(script);
            return true;
        }else{
            var http = this.$http();
            http.get(filePath, null);
            if(typeof http.exception != "undefined") return false;

            if (http.readyState() == 4 &&
                (http.status() == 200 || http.status() == 304)) {
                script.text = http.responseText();
                head.appendChild(script);
                head.removeChild(script);
                if(typeof callback == "function") callback();
                return true;
            }

            http.close();
            
            return false;
        }
    };

    // Detect browser type
    var ua = navigator.userAgent.toLowerCase(), s;
    var b = (s = ua.match(/msie ([\d.]+)/)) ? this.ie = s[1] :
        (s = ua.match(/firefox\/([\d.]+)/)) ? this.firefox = s[1] :
        (s = ua.match(/chrome\/([\d.]+)/)) ? this.chrome = s[1] :
        (s = ua.match(/opera.([\d.]+)/)) ? this.opera = s[1] :
        (s = ua.match(/version\/([\d.]+).*safari/)) ? this.safari = s[1] : 0;
    
    // Detect jsvm home
    var script = document.getElementById("j$vm");
    var j$vm_src = script.src;
    var p = script.src.lastIndexOf("/");
    if (p != -1) {
        j$vm_home = script.src.substring(0, p);
    } else {
        alert("Can't find jsvm home");
    }
    j$vm_classpath = script.getAttribute("classpath");

    // Load the third party libraries in classpath
    if(j$vm_classpath && j$vm_classpath.length >0){
        var libs = j$vm_classpath.split(";"), filePath, lib;
        for(var i=0, len=libs.length; i<len; i++){
            lib = libs[i];
            if(lib.length == 0) continue;
            filePath = home + "/" + lib;
            if(!this.$load(filePath, false)){
                if(typeof System != "undefined"){
                    System.err.println("Can't load library from "+filePath);
                }
            }
        }
    }

    this.$home = function (){
        return j$vm_home;
    };

    this.$classpath = function (){
        return j$vm_classpath;
    };

    j$package = function(packageName){
        J$VM.$package(packageName);
    };

    j$import = function(className){
        J$VM.$import(className);
    };

};


以上的代码中涉及到XHR的部分放在js.net.HttpURLConnection中,如下:


/**
 *
 * @File: HttpURLConnection.js
 * @Create: 2010-11-17
 * @Author: hoodng@gmail.com
 */


j$package("js.net");

js.net.HttpURLConnection = function(){

    var _xhr, _timeout = 30000;

    var _check = function(){
        if(typeof _xhr === "undefined")
            throw new Error("The XMLHttpRequest is null");
    };

    this.getAllResponseHeaders = function(){
        _check();

        return _xhr.getAllResponseHeaders();
    };

    this.getResponseHeader = function(key){
        _check();

        return _xhr.getResponseHeader(key);
    };

    this.setRequestHeader = function(key, value){
        _check();

        _xhr.setRequestHeader(key, value);
    };


    this.responseText = function(){
        _check();
        
        return _xhr.responseText;
    };

    this.responseXML = function(){
        _check();
        
        return _xhr.responseXML;
    };

    this.status = function(){
        _check();
        
        return _xhr.status;
    };

    this.readyState = function(){
        _check();

        return _xhr.readyState;
    };

    this.statusText = function(){
        _check();

        return _xhr.statusText;
    };

    this.getTimeout = function(){
        return _timeout;
    };

    this.setTimeout = function(timeout){
        _timeout = timeout;
    };
    
    this.close = function(){
        if(this.__timer__ != undefined){
            clearTimeout(this.__timer__);
            this.__timer__ = undefined;
        }

        _xhr = undefined;
    };
    
    var _makeQueryString = function(params){
        if(params == null) return null;

        var buf = new js.lang.StringBuffer();
        for(var p in params){
            buf.append(p).append("=").append(params[p]).append("&");
        }
        buf.append("_=").append(new Date().getTime());

        return buf.toString();
    };

    var _onreadystatechange = function(xhr, thi$, callback, errback){
        if(xhr.readyState == 4){

            if(this.__timer__ != undefined){
                clearTimeout(this.__timer__);
                this.__timer__ = undefined;
            }

            if(xhr.status == 200 || xhr.status == 304){
                callback.call(thi$, this);
            }else{
                if(typeof errback == "function"){
                    errback.call(thi$, this);
                }
            }
        }
    };

    var _ontimeout = function(xhr, thi$, tmoutback){
        xhr.abort();
        xhr = undefined;

        if(typeof tmoutback == "function"){
            tmoutback.call(thi$);
        }
    };

    /**
     * @param url
     * @param params, VO of query string
     * @param thi$, callback scope
     * @param callback, success callback
     * @param errback, error callback
     * @param tmoutback, timeout callback
     * If did not specify thi$, callback and errback, this method is
     * synchronized
     */

    this.post = function(url, params, thi$, callback, errback, tmoutback){
        _check();

        var query = _makeQueryString(params), async = false;

        if(typeof callback === "function"){
            async = true;

            _xhr.onreadystatechange = _onreadystatechange.$bind(
                this, false, _xhr, thi$, callback, errback, tmoutback);
        }

        this.setRequestHeader("Content-Type",
                              "application/x-www-form-urlencoded");

        if(async && typeof tmoutback == "function"){
            js.lang.Thread.$yield(this, _ontimeout, _timeout, _xhr, thi$, tmoutback);
        }

        try{
            _xhr.open("POST", url, async);
            _xhr.send(query);
        } catch (x) {
            this.exception = x;
            if(typeof errback == "function"){
                errback.call(thi$, this);
            }
            this.close();
        }

    };
    
    /**
     * @see this.post(url, params, thi$, callback, errback, tmoutback)
     */

    this.get = function(url, params, thi$, callback, errback, tmoutback){
        _check();

        var query = _makeQueryString(params), async = false;
        if(query != null){
            url += ("?" + query);
        }

        if(typeof callback === "function"){
            async = true;

            _xhr.onreadystatechange = _onreadystatechange.$bind(
                this, false, _xhr, thi$, callback, errback, tmoutback);
        }

        try{
            _xhr.open("GET", url, async);
            _xhr.send(null);
            
        } catch (x) {
            this.exception = x;
            if(typeof errback == "function"){
                errback.call(thi$, this);
            }
            this.close();
        }

    };

    _xhr = (typeof window.XMLHttpRequest != "undefined") ?
        new XMLHttpRequest() : function(){
            var _ = js.net.HttpURLConnection;
            if(_.PROGID != undefined){
                return new ActiveXObject(_.PROGID);
            }else{
                for (var i = 0; i < _.PROGIDS.length; i++) {
                    _.PROGID = _.PROGIDS[i];
                    try {
                        return new ActiveXObject(_.PROGID);
                    } catch (ex) {
                        // Nothing to do

                    }
                }
                return undefined;
            }
        }();

}.$extend(js.lang.Object);

js.net.HttpURLConnection.PROGID = undefined;
js.net.HttpURLConnection.PROGIDS = ["MSXML2.XMLHTTP.6.0",
                                    "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];


阅读(2085) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~