JS设计模式——7.工厂模式(示例-XHR)

XHR工厂

基本实现

var AjaxHandler = new Interface('AjaxHandler', ['request', 'createXHR']);
var SimpleHandler = function(){};
SimpleHandler.prototype = {
    request: function(method, url, callback, postVars){
        var xhr = this.createXHR();
        xhr.onreadystatechange = function(){
            if(xhr.readyState!==4) return;
            (xhr.status===200)?
                callback.success(xhr.responseText, xhr.responseXML):
                callback.failure(xhr.status);
        };
        xhr.open(method, url, true);
        if(method !== 'POST') postVars = null;
        xhr.send(postVars);
    },
    createXHR: function(){
        var methods = [
            function() {return new XMLHttpRequest();},
            function() {return new ActiveXObject('Msxml2.XMLHTTP');},
            function() {return new ActiveXObject('Microsoft.XMLHTTP');}
        ];
        for(var i = 0, len=methods.length; i<len; i++){
            try{
                methods[i]();
            }catch (e){
                continue;
            }
            this.createXHR = methods[i]; //memoize the method.
            return methods[i];
        }
    }
};

createXHR这个工厂方法根据当前的宿主环境返回适当的xhr对象.重点是createXHR在首次执行之后就被替换为了methods[i],这个就是memoizing技术了(可以称称之为记录).这样当我们下次用到createXHR的时候就不用在去能力检测了.大大的提升了性能.

SimpleHandler的调用如下:

var myHandler = new SimpleHandler();
var callback = {
    success: function(responseText){
        console.log('Success' + responseText);
    },
    failure: function(statusCode){
        console.log('Failure' + statusCode);
    }
};
myHandler.request('GET', 'stript.php', callback);

专用型连接对象

我们对上面的对象进行一个扩展,以便根据网络条件创建专门的请求对象.

首先我们先来创建两个新的处理器类:

1:QueHandler会在发起新的请求之前先确保所有请求都已经成功处理.

var QueHandler = function(){
    this.queue = [];
    this.requestInProgress = false;
    this.retryDelay = 5;
};
extend(QueHandler, SimpleHandler);
QueHandler.prototype.request = function(method, url, callback, postVars, override){
    if(this.requestInProgress && !override){
        this.queue.push({
            method: method,
            url: url,
            callback: callback,
            postVars: postVars
        });
    }else{
        this.requestInProgress = true;
        var xhr = this.createXHR();
        var that = this;
        xhr.onreadystatechange = function(){
            if(xhr.readyState !== 4) return;
            if(xhr.status === 200){
                callback.success(xhr.responseText, xhr.responseXML);
                that.advanceQueue();
            }else{
                callback.failure(xhr.status){
                    setTimeout(function(){that.request(method, url, callback, postVars, true);}, that.retryDelay*1000);
                }
            }
        };
        xhr.open(method, url, true);
        if(method!=='POST') postVars = null;
        xhr.send(postVars);
    }
};
QueHandler.prototype.advanceQueue = function(){
    if(this.queue.length === 0){
        this.requestInProgress = false;
        return;
    }
    var req = this.queue.shift();
    this.request(req.method, req.url, req.callback, req.postVars, true);
};

2:OffHandler会在用户处于离线状态时把请求缓存起来.

var OffHandler = function(){
    this.storedRequests = [];
};
extend(OffHandler, SimpleHandler);
OffHandler.prototype.request = function(method, url, callback, postVars){
    if(XhrManager.isOffline()){
        this.storedRequests.push({
            method:method,
            url:url,
            callback:callback,
            postVars:postVars
        });
    }else{
        this.flushStoredRequests();
        OffHandler.superclass.request(method, url, callback, postVars);
    }
};
OffHandler.prototype.flushStoredRequests = function(){
    for(var i= 0, len=this.storedRequests.length; i<len; i++){
        var req = this.storedRequests[i];
        OffHandler.superclass.request(req.method, req.url, req.callback, req.postVars);
    }
}

在运行时选择连接对象

现在该用到工厂模式了.因为程序元根本不知道各个最终用户面临的网络条件,所以要用一个工厂在运行是选择最合适的类.

var XhrManager = {
    createXhrHandler: function(){
        var xhr;
        if(this.isOffline()){
            xhr = new OffHandler();
        }else if(this.isHighLatency()){
            xhr = new QueHandler();
        }else{
            xhr = new SimpleHandler();
        }
        Interface.ensureImplements(xhr, AjaxHandler);
        return xhr;
    },
    isOffline: function(){ //do a quick request with SimpleHandler and see if it success.
        ...
    },
    isHighLatency: function(){ //do a series of requests with SimpleHandler and time the requests,Best done once, as a branching function.
        ...
    }
};
var myHandler = XhrManager.createXhrHandler();
var callback = {};
myHandler.request('GET', 'sript.php', callback);

我只想说他的isOffline的实现亮了.

XHR的三个重要属性

posted @ 2014-03-28 16:50  JChen___  阅读(343)  评论(0编辑  收藏  举报