含簡單鏈式調用的ajax類庫思路及寫法

在寫類庫前 我們一定要理清楚我們寫的類庫,傳遞的參數代表什麼意思
然後在封裝的時候,首先考慮的就是兼容性的問題,整體的構思
我的整體的代碼分3個模塊,
1:ajax核心模塊;
2:util幫助庫(用來解決兼容性問題)
3:鏈式寫法Promise(由於本人對鏈式寫法研究有限,故只能鏈式調用兩個)
在ajax核心模塊方面,主要是對ajax裏面傳遞進來的參數進行了統一處理
如是否走緩存,是否是get系的方法,發送的數據如何處理等,統一的都在ajax核心模塊裏面處理,然後再調用ajax的4部曲 完成數據交互
具體代碼及詳細註釋如下

/**
 * Created by pengrongshu-pc on 2015/9/20.
 */
(function () {
    if (this.$http)return;
    this.$http = function (setting) {
        if(!util.isObject(setting))return;
        //設置默認值
        var defaultOption={
            type:'GET',//設置交互方式
            url:'',
            data:'',
            cache:false,//默認不走緩存
            async:true,//默認爲異步方式
            username:undefined,
            password:undefined,
            header:{},//默認爲空 看用戶 需不需要設置頭信息
            success:function(){},//AJAX請求成功就執行
            error:function(){},//ajax請求失敗執行
            beforeSend: function () {
            },//在發送前執行
            complete: function () {
            },//完成就執行
            contentType: 'application/x-www-form-urlencoded',//給form表格用的
            mimeType: '',//一個mime類型用來覆蓋XHR的 MIME類型
            statusCode: {},//狀態碼
            timeout: 0,//規定響應完成的最大時間
            context: window,//上下文
            dataType: 'text'//傳進來的data是什麼數據格式的
        },tempVal;
        //遍歷默認值
        util.traverse(defaultOption,function(key){
            defaultOption[key]=setting[key]||defaultOption[key]
        });
        //獲取XHR
        var deferred=new Deferred();
        var xhr=util.getXhR();
        //處理 傳遞進來的參數 所要對應的操作
        //如果不走緩存 我就在url後面加個隨機數
        //那麼 就要判斷url  有沒有問號
        if(!defaultOption.cache){
            defaultOption.url=util.hasQuestionMark(defaultOption.url,'_='+(Math.random() * 0xffffff | 0))
        }
        //處理data前 要處理指定方法是什麼類的get 或者post處理不同
        var methodReg=/^(get|post|delete|put|head)$/igm;
        //判斷處理進來的f方法是否合法、
        if(!(methodReg.test(defaultOption.type))){
            throw  new Error('data Parameter error');
        }
        //不管是get系還是post系 都要轉成uri格式 只是放的位置不同 data前提要是對象
        if(util.isObject(defaultOption.data)){
            tempVal=[];
            util.traverse(defaultOption.data,function(key,value){
                tempVal.push(encodeURIComponent(key)+'='+encodeURIComponent(value));
            });
            //將data改變爲uri格式了
            defaultOption.data=tempVal.join('&')
        }
        //判斷是不是get系
        var getReg=/^(get|put)$/igm;
        if(getReg.test(defaultOption.type.toLocaleLowerCase())){
            //說明是get系 get系將 數據放置到url後面 xhr.send 是不需要傳遞參數的data就可以清理了
            defaultOption.url=util.hasQuestionMark(defaultOption.url,defaultOption.data);
            defaultOption.data=void 0;
        }

        //處理完參數 開始ajax核心
        xhr.open(defaultOption.type,defaultOption.url,defaultOption.async,defaultOption.username,defaultOption.password);
        /*這裏不懂跟後臺怎麼用*/
        defaultOption.contentType && (defaultOption.header['content-type'] = defaultOption.contentType);
        //自定義頭信息
        util.traverse(defaultOption.header, function (key, value) {
            xhr.setRequestHeader && xhr.setRequestHeader(key, value);
        });
        /*這裏不懂怎麼跟後臺用  結束*/
        //改變this關鍵字
        defaultOption.success=util.bind(defaultOption.success,defaultOption.context);
        defaultOption.error=util.bind(defaultOption.error,defaultOption.context);
        //成功失敗統一處理
        var __suc = function (context, headers) {
            defaultOption.success(context, headers);
            defaultOption.complete(context, headers);
            deferred.promise.onsuccess(context,headers);
        };
        var __err = function (status, headers) {
            defaultOption.error(status, headers);
            defaultOption.complete(status, headers);
            deferred.promise.onerror(status,headers)
        };
        // 重寫mime類型
        defaultOption.mimeType && xhr.overrideMimeType(defaultOption.mimeType);
        // 開始ajax 處理
        xhr.onreadystatechange=function(){
            //readyState 分4個階段 =4即 ajax完成 只是說ajax流程走完了
            if(xhr.readyState===4){
                //獲取不同的狀態碼  不同的狀態碼 對應不同 的操作
                //這個是我們用戶自己傳遞的方法
                tempVal=defaultOption.statusCode[xhr.status];
                util.isFunction(tempVal)&&tempVal();
                //獲取後臺返回的數據
                tempVal=xhr.responseText;
                //再判斷成功與否
                if(/^2\d{2}$/.test(xhr.status)){
                    //2開頭表示成功,再判斷返回的是否是一個json
                    if(defaultOption.dataType.toLocaleLowerCase()==='json'){
                        try{
                            tempVal=util.parse(tempVal);
                        }catch(err){
                            defaultOption.error(arguments);
                        }
                    }
                    //將獲取到的數據和頭信息 返回給成功函數 成功函數 裏面 怎麼做 是由我們自己決定的
                    __suc(tempVal,xhr.getAllResponseHeaders());
                }
            }
        }
        //ajax 請求是否超時判斷
        if(defaultOption.timeout>500){
            //最慢也要五百毫秒用
            if('timeout'in xhr){
                //判斷xhr 裏面有沒有 timeout屬性
                xhr.timeout=defaultOption.timeout;
                xhr.ontimeout=function(){
                    //超過規定的時間 不管有沒有完成 我們都報一個失敗回去
                    __err(arguments);//你想給失敗傳什麼就傳什麼
                }
            }else{
                //沒有就是低版本瀏覽器
                window.setTimeout(function(){
                    if(!xhr.readyState==4){
                        //強制結束ajax
                        xhr.abort();
                        //再報一個失敗回去
                        __err(arguments);
                    }
                },defaultOption.timeout)
            }
        };
        defaultOption.beforeSend(xhr);//在發送前執行,具體執行什麼操作 由我們自己決定
        xhr.send(defaultOption.data);
        //以上ajax 全部完成
        //供鏈式寫法用
        return deferred
    }
    util = {
        parse:(function(){
            if(window.JSON){
                return function(text){
                    return JSON.parse(text);
                }
            }
            return function(text){
                return (new Function('return '+text))()
            }
        })(),
        bind:function(fn,context){
            //就是用來改變this關鍵字
            if(Function.prototype.bind){
                return fn.bind(context)
            }else{
                return function(){
                    fn.apply(context,arguments)
                }
            }
        },
        each: (function () {
            if ([].forEach) {
                //如果數組中存在 forEach則
                //forEach是可以傳遞兩個參數的一個回調 一個爲回調的上下文
                return function (list) {
                    [].forEach.call(list, arguments[1], arguments[2])
                }
            }
            return function (list, callback) {
                for (var i = 0; i < list.length; i++) {
                    callback.call(arguments[2], list[i], i, list)
                }
            }
        })(),
        isType: function (type) {
            return function (obj) {
                return Object.prototype.toString.call(obj) == '[object ' + type + ']';
            }
        },
        //動態創建方法
        init: function () {
            util.each(['Array', 'Object', 'Function', 'String'], function (item) {
                //現在util.isArray...就是一個方法了 方法的內容是 function(obj){ return Object.prototype.toString.call(obj) == '[Object ' + type+']';}
                util['is' + item] = util.isType(item)
            })
        },
        forIn: function (obj, callback) {
            if (!util.isObject(obj))return;
            for (var key in obj) {
                if (!obj.hasOwnProperty(key))continue;
                callback.call(null, key, obj[key])
            }
        },
        traverse: function (obj) {
            //可以傳隨意參數
            if (util.isArray(obj)) {
                //第一個參數 改變的是裏面所調用方法的指向
                return util.each.apply(null, arguments);
            }
            if(util.isObject(obj)){
                return util.forIn.apply(null,arguments);
            }
        },
        getXhR:(function(){
            var list = [function () {
                return new XMLHttpRequest();
            }, function () {
                return new ActiveXObject('Microsoft.XMLHTTP');
            }, function () {
                return new ActiveXObject('MsXML2.XMLHTTP');
            }, function () {
                return new ActiveXObject('MsXML3.XMLHTTP');
            }];
            for(var i=0;i<list.length;){
                try{
                    return list[i]
                }catch(err){
                    continue;
                }
            }
        })(),
        hasQuestionMark:function(str,data){
            var reg=/\?/igm;
            var temp='';
            if(reg.test(str)){
                //有有問號
                temp='&';
            }else{
                //沒有問號
                temp='?';
            }
            //將拼接好的url返回
            return str+temp+data;
        }
    }
    //init執行了纔會動態創建那些方法
    util.init();
    //鏈式寫法
    var Promise=function(){
        this.onSuccess=this.onerror=new Function;//兩個都是一個空函數
        this.isPromis=true;
    }
    Promise.prototype.success=function(fn){
        if(util.isFunction(fn)){
            this.onsuccess=fn;
        }
    }
    Promise.prototype.error=function(fn){
        if(util.isFunction(fn)){
            this.onerror=fn;
        }
    }
    var Deferred = function () {
        this.promise = new Promise();
        this.status = 'uninit';
    };
    Deferred.prototype.done = function (func) {
        this.status = 'done';
        this.promise.success(func);
        return this;
    };
    Deferred.prototype.fail = function (func) {
        this.status = 'fail';
        this.promise.error(func);
        return this;
    };
    util.each(['get', 'post', 'getScript'], function (item) {
        $http[item] = function (url, data, callback, datatype) {
            if (item == 'getScript') {
                item = 'get';
                var __callback = callback;
                callback = function (data) {
                    (new Function(data))();
                    __callback(data)
                }
            }
            return $http({
                type: item,
                url: url,
                data: data,
                success: callback,
                dataType: datatype
            });
        }
    })
})()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章