先定一個小目標,自己封裝個ajax

來源:互聯網
上載者:User

標籤:nbsp   ret   delete   class   性問題   字元   createjs   log   回調   

你是否發現項目中有很多頁面只用到了架構不到十分之一的內容,還引了壓縮後還有70多kb的jquery庫你是否發現項目中就用了兩三個underscore提供的方法,其他大部分的你方法你甚至從來沒有看過你是否發現fetch好像比ajax好用那麼一點你是否想過自己封裝個ajax.... 純前端寫得久了,便想折騰點事情。比如先定一個小目標,年前自己寫個類jquery輕量級庫.... 那麼就從自己封裝一個ajax切入吧,首先我整理的一個思維導圖,一目瞭然

 

解析參數資料通常我們的請求後面會有一些參數,如果是get請求當然可以直接通過‘&‘拼在url後面。那麼post就需要做一下處理了,如果參數是字串,則將字串用‘&’符號切割轉化成索引值對形式,同時用encodeURIComponent轉碼,最後類似於jquery的處理,將/%20/g(空格)替換成‘+‘。
      getData: function(){                var name, value;                if (opts.data) {                    if (typeof opts.data === "string") {                        opts.data = opts.data.split("&");                        for (var i = 0, len = opts.data.length; i < len; i++) {                            name = opts.data[i].split("=")[0];                            value = opts.data[i].split("=")[1];                            opts.data[i] = encodeURIComponent(name) + "=" + encodeURIComponent(value);                        }                        opts.data = opts.data.replace("/%20/g", "+");                    } else if (typeof opts.data === "object") {                        var arr = [];                        for (var name in opts.data) {                            var value = opts.data[name].toString();                            name = encodeURIComponent(name);                            value = encodeURIComponent(value);                            arr.push(name + "=" + value);                        }                        opts.data = arr.join("&").replace("/%20/g", "+");                    }                    //使用GET方法或JSONP,則手動添加到URL中                    if (opts.type === "GET" || opts.dataType === "jsonp") {                        opts.url += opts.url.indexOf("?") > -1 ? opts.data : "?" + opts.data;                    }                }            },

 

建立jsonp如果dataType為jsonp的話,其實我們就可以理解為不是ajax請求了,而是偽造了一個script標籤,通過script的src屬性相當於發起了一個請求,其中帶了一個callback(這裡是名稱叫jsonp_timeName)的參數,最終約定好背景資料包通過jsonp_name(data)這種形式包裹起來,這樣就相當於前端再回調了一個jsonp_name的方法,將資料通過參數的形式帶過來了,所以前端js需要實現一個名叫jsonp_name的方法。其實jsonp跨域的方法有很多種,比如還有偽造iframe等,跨域詳情解決方案可以參考我的博文 http://www.cnblogs.com/liliangel/p/5760426.html 
      createJsonp: function(){                var script = document.createElement("script"),                    timeName = new Date().getTime() + Math.round(Math.random() * 1000),                    callback = "jsonp_" + name;                window[callback] = function(data) {                    clearTimeout(ajax.options.timeoutFlag);                    document.body.removeChild(script);                    try {                        data && (data = JSON.parse(data));                    } catch (e) {                        console.error(‘ajax error for json parse responseText‘);                    }                      ajax.success(data);                }                script.src = url +  (url.indexOf("?") > -1 ? "" : "?") + "callback=" + callback;                script.type = "text/javascript";                document.body.appendChild(script);                ajax.timeout(callback, script);           },

 

建立XHR首先通過相容性處理的getXHR()方法得到xhr對象,接著佈建要求頭,區分post、get。每當 readyState 改變時,就會觸發 onreadystatechange 事件,readyState 屬性存有 XMLHttpRequest 的狀態資訊。這裡我相當於重寫readystate事件監聽,來做我自己的相應邏輯處理,由於執行abort()方法後,有可能觸發onreadystatechange事件,所以設定一個ajax.options.timeoutBool標識,來忽略中止觸發的事件。最後調用xhr的send()方法發送出請求,同時渲染timeout()方法。
    createXHR: function(){                //建立對象                xhr = ajax.getXHR();                xhr.open(opts.type, opts.url, opts.async);                //佈建要求頭                if (opts.type === "POST" && !opts.contentType) {                    //若是post提交,則設定content-Type 為application/x-www-four-urlencoded                    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");                } else if (opts.contentType) {                    xhr.setRequestHeader("Content-Type", opts.contentType);                }                //添加監聽                xhr.onreadystatechange = function() {                    if (xhr.readyState === 4) {                        if (opts.timeout !== undefined) {                            //由於執行abort()方法後,有可能觸發onreadystatechange事件,所以設定一個ajax.options.timeoutBool標識,來忽略中止觸發的事件。                            if (ajax.options.timeoutBool) {                                return;                            }                            clearTimeout(ajax.options.timeoutFlag);                        }                        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {                            var responseText = xhr.responseText;                            try {                                xhr.responseText && (responseText = JSON.parse(responseText));                                opts.success(responseText);                            } catch (e) {                                console.error(‘ajax error for json parse responseText‘);                                //opts.error(xhr);                            }                                   } else {                            opts.error(xhr);                        }                    }                };                //發送請求                xhr.send(opts.type === "GET" ? null : opts.data);                ajax.timeout(); //請求逾時                }

 

相容IE6擷取xhr對象可能會存在低版本ie相容性問題,為此這樣判斷處理一下
      getXHR: function(){                if (window.XMLHttpRequest) {                    return new XMLHttpRequest();                } else {                    //遍曆IE中不同版本的ActiveX對象                    var versions = ["Microsoft", "msxm3", "msxml2", "msxml1"];                    for (var i = 0; i < versions.length; i++) {                        try {                            var version = versions[i] + ".XMLHTTP";                            return new ActiveXObject(version);                        } catch (e) {                            console.log(‘error ajax‘,e)                        }                    }                }            }

 

佈建要求逾時

前面我定義了一個全域的屬性timeoutFlag,這裡通過settimeout延時函數給它賦值。如果是jsonp,則移除原來追加的script標籤,否則通過全域的xhr條用abort()方法終止正在發送的請求!

    timeout: function(callback, script){                if (opts.timeout !== undefined) {                    ajax.options.timeoutFlag = setTimeout(function() {                        if (opts.dataType === "jsonp") {                            delete window[callback];                            document.body.removeChild(script);                        } else {                            ajax.options.timeoutBool = true;                            xhr && xhr.abort();                        }                    }, opts.timeout);                }            },
全域變數
var defaultOpts = {            url: ‘‘, //ajax 請求地址            type : ‘GET‘, //請求的方法,預設為GET            data : null, //請求的資料            contentType : ‘‘,//要求標頭            dataType : ‘json‘, //請求的類型,預設為json            async : true, //是否非同步,預設為true            timeout: 5000, //逾時時間,預設5秒鐘            before : function() {                console.log(‘before‘)            }, //發送之前執行的函數            error: function() {                console.log(‘error‘)            }, //錯誤執行的函數            success: function() {                console.log(‘success‘)            } //請求成功的回呼函數        }        for (i in defaultOpts) {            if (opts[i] === undefined) {                opts[i] = defaultOpts[i];            }        }    var xhr = null;    options: {                timeoutFlag: null, //逾時標識                timeoutBool: false //是否請求逾時            },

 

初始化調用我這裡是用物件導向函數方式寫的,核心初始化代碼如下:
init: function(){                opts.before();                ajax.getData();                opts.dataType === "jsonp" ? ajax.createJsonp() : ajax.createXHR();            },    ajax.init();
設定AMD等規範如果是用requireJS這種方法引用,那麼還需要設定一下amd、cmd或者commonJs規範
// AMD && CMD    if(typeof define === ‘function‘){        define(function(){            return li;        });    // CommonJS    }else if(typeof module !== "undefined" && module !== null){        module.exports = li;    // window    }else{        window.li = li;    }

 

調用樣本調用樣本,我這裡只貼出非同步方式,當然還有好幾種情況,比如出錯等,這裡不一一展示 預設為gety非同步請求,逾時時間5秒鐘。before為請求前執行的函數,通常我們可以寫統一的loading動畫。當發生405/500等這種錯誤時,會調用error方法,當然我們通常在success回呼函數裡做邏輯處理。這裡盡量跟jquery庫的ajax封裝保持一致,是為了更符合原有的開發編碼習慣 

 

結果控制台輸出如下:

 

我這裡用$這個符合作為全域對象引入,也是為了更符合原來用jquery的編碼習慣,但是這裡只實現了其中的ajax方法哦,其他項目中高頻出現的方法,以及常用的小工具後續慢慢補充.... 代碼已上傳github https://github.com/helijun/component/tree/master/li

先定一個小目標,自己封裝個ajax

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.