1. 程式人生 > >第111天:Ajax之jQuery實現方法

第111天:Ajax之jQuery實現方法

自己 tro 三個參數 == get請求 search 創建 第一個 崩潰

由於jQuery中的Ajax方法是用了內置的deferred模塊,是Promise模式的一種實現,而我們這裏沒有講過,所以我們就不使用這一模式啦。

我們只定義一個Ajax方法,他可以簡單的getpostjsonp請求就可以了。

一、jQuery語法格式

 1 var ajax = function () {
 2     
 3   //  做一些初始化,定義一些私有函數等
 4  
 5   return function () {
 6     // ajax主體代碼
 7   }
 8     
 9 }()
10 
11 
12 ajax({
13   url: myUrl,
14   type
: ‘get, 15 dataType: ‘json, 16 timeout: 1000, 17 success: function (data, status) { 18 console.log(data) 19 }, 20 fail: function (err, status) { 21 console.log(err) 22 } 23 })

二、初始化屬性

Ajax方法需要傳遞一個對象進去,這個對象中我們可以定義一些我們希望的屬性,我們就必須初始一下各種屬性

 1 //默認請求參數
 2   var _options = {
 3     url: null
, // 請求連接 4 type: ‘GET‘, // 請求類型 5 data: null, // post時請求體 6 dataType: ‘text‘, // 返回請求的類型,有text/json兩種 7 jsonp: ‘callback‘, // jsonp請求的標誌,一般不改動 8 jsonpCallback: ‘jsonpCallback‘, //jsonp請求的函數名 9 async: true, // 是否異步 10 cache: true, // 是否緩存 11 timeout:null, // 設置請求超時 12 contentType
: ‘application/x-www-form-urlencoded‘, 13 success: null, // 請求成功回調函數 14 fail: null // 請求失敗回調 15 }

三、Ajax主體函數

以上我們定義了一大串請求有關的數據,接下來我們就開始Ajax主體函數的書寫,現在的Ajax方法是這樣了

 1 var ajax = function () {
 2 
 3   //默認請求參數
 4   var _options = {
 5     url: null,
 6     type: ‘GET‘,
 7     data: null,
 8     dataType: ‘text‘,
 9     jsonp: ‘callback‘,
10     jsonpCallback: ‘jsonpCallback‘,
11     async: true,
12     cache: true,
13     timeout:null,
14     contentType: ‘application/x-www-form-urlencoded‘,
15     success: null,
16     fail: null
17   }
18   // ...
19   return function (options) {
20      // ...
21   }
22 }()

四、內部繼承

我們可以想一下,ajax方法傳遞一個對象進來,我們需要把我們設置的這個對象上的屬性來覆蓋掉初始化_options上面的那些屬性呢,肯定需要。那下面我們先寫一個簡單的繼承,如下:

 1 var ajax = function () {
 2 
 3   //默認請求參數
 4   var _options = {
 5     url: null,
 6     type: ‘GET‘,
 7     data: null,
 8     dataType: ‘text‘,
 9     jsonp: ‘callback‘,
10     jsonpCallback: ‘jsonpCallback‘,
11     async: true,
12     cache: true,
13     timeout:null,
14     contentType: ‘application/x-www-form-urlencoded‘,
15     success: null,
16     fail: null
17   }
18   //  內部使用的繼承方法
19   var _extend = function(target,options) {
20     if( typeof target !== ‘object‘ || typeof options !== ‘object‘ ) {
21       return;
22     }
23     var copy ,clone, name;
24     for( name in options ) {
25       if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
26         target[name] = options[name];
27       }
28     }
29     return target;
30   };
31 
32 
33   // ...
34   return function (options) {
35 
36     // 沒有傳參或者沒有url,拋出錯誤
37     if( !options || !options.url ) {
38       throw(‘參數錯誤!‘);
39     }
40 
41     // 繼承操作
42     options.type = options.type.toUpperCase();
43     _extend(options,_options);
44      // ...
45   }
46 }()

這個繼承方法,我們是把初始化的_options繼承到了options,為什麽呢?因為我們這個_options對象不在ajax方法內部,我們需要使用它,但我們不能改變他,如果改變了他,下一次使用ajax方法將會崩潰。因此,我們僅僅是把配置的options對象沒有的屬性設置為初始值。

五、jsonp請求

jsonp請求不是xhr請求,他是將請求url當做script標簽的src值插入到頁面body中去實現的,我們先把jsonp請求處理一下再開始建立xhr請求的代碼吧。

 1 var ajax = function () {
 2 
 3   //默認請求參數
 4   var _options = {
 5     url: null,
 6     type: ‘GET‘,
 7     data: null,
 8     dataType: ‘text‘,
 9     jsonp: ‘callback‘,
10     jsonpCallback: ‘jsonpCallback‘,
11     async: true,
12     cache: true,
13     timeout:null,
14     contentType: ‘application/x-www-form-urlencoded‘,
15     success: null,
16     fail: null
17   }
18   //  內部使用的繼承方法
19   var _extend = function(target,options) {
20     if( typeof target !== ‘object‘ || typeof options !== ‘object‘ ) {
21       return;
22     }
23     var copy ,clone, name;
24     for( name in options ) {
25       if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
26         target[name] = options[name];
27       }
28     }
29     return target;
30   };
31   
32   // jsonp處理函數
33   function _sendJsonpRequest(url,callbackName,succCallback) {
34 
35     var script = document.createElement(‘script‘);
36 
37     script.type="text/javascript";
38     script.src=url;
39 
40     document.body.appendChild(script);
41     // 如果用戶自己定義了回調函數,就用自己定義的,否則,調用success函數
42     window[callbackName] = window[callbackName] || succCallback;
43 
44   }
45 
46   // ...
47   return function (options) {
48 
49     // 沒有傳參或者沒有url,拋出錯誤
50     if( !options || !options.url ) {
51       throw(‘參數錯誤!‘);
52     }
53 
54     // 繼承操作
55     options.type = options.type.toUpperCase();
56     _extend(options,_options);
57 
58     /*jsonp部分,直接返回*/
59     if( options.dataType === ‘jsonp‘ ) {
60       var jsonpUrl = options.url.indexOf(‘?‘) > -1 ? options.url: options.url +
61         ‘?‘ + options.jsonp+ ‘=‘ + options.jsonpCallback;
62 
63      return  _sendJsonpRequest(jsonpUrl,options.jsonpCallback,options.success);
64       
65     }
66      // ...
67   }
68 }()

我們定義了一個_sendJsonpRequest函數,這個函數接收三個參數,第一個是jsonpUrl,第二個是jsonp的回調函數名,第三個是成功回調函數,我們在這個函數內建立一個srcjsonpUrlscript元素插入到body中,同時,確定了回調函數(如果我們定義了jsonpCallback函數就調用它,如果沒有就調用success回調,一般情況我們不去定義全局的jsonpCallback函數而傳遞success回調來完成jsonp請求)。

六、xhr請求處理

好,處理好jsonp請求後,我們開始處理xhr請求了。

  1 var ajax = function () {
  2 
  3   //默認請求參數
  4   var _options = {
  5     url: null,
  6     type: ‘GET‘,
  7     data: null,
  8     dataType: ‘text‘,
  9     jsonp: ‘callback‘,
 10     jsonpCallback: ‘jsonpCallback‘,
 11     async: true,
 12     cache: true,
 13     timeout:null,
 14     contentType: ‘application/x-www-form-urlencoded‘,
 15     success: null,
 16     fail: null
 17   }
 18   //  內部使用的繼承方法
 19   var _extend = function(target,options) {
 20     if( typeof target !== ‘object‘ || typeof options !== ‘object‘ ) {
 21       return;
 22     }
 23     var copy ,clone, name;
 24     for( name in options ) {
 25       if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
 26         target[name] = options[name];
 27       }
 28     }
 29     return target;
 30   };
 31   
 32   // jsonp處理函數
 33   function _sendJsonpRequest(url,callbackName,succCallback) {
 34 
 35     var script = document.createElement(‘script‘);
 36 
 37     script.type="text/javascript";
 38     script.src=url;
 39 
 40     document.body.appendChild(script);
 41     // 如果用戶自己定義了回調函數,就用自己定義的,否則,調用success函數
 42     window[callbackName] = window[callbackName] || succCallback;
 43 
 44   }
 45   
 46   // json轉化為字符串
 47   var _param = function(data) {
 48     var str = ‘‘;
 49     if( !data || _empty(data)) {
 50       return str;
 51     }
 52     for(var key in data) {
 53       str += key + ‘=‘+ data[key]+‘&‘
 54     }
 55     str = str.slice(0,-1);
 56     return str;
 57   }
 58   //判斷對象是否為空
 59   var _empty = function(obj) {
 60     for(var key in obj) {
 61       return false;
 62     }
 63     return true;
 64   }
 65 
 66   // ...
 67   return function (options) {
 68 
 69     // 沒有傳參或者沒有url,拋出錯誤
 70     if( !options || !options.url ) {
 71       throw(‘參數錯誤!‘);
 72     }
 73 
 74     // 繼承操作
 75     options.type = options.type.toUpperCase();
 76     _extend(options,_options);
 77 
 78     /*jsonp部分,直接返回*/
 79     if( options.dataType === ‘jsonp‘ ) {
 80       var jsonpUrl = options.url.indexOf(‘?‘) > -1 ? options.url: options.url +
 81         ‘?‘ + options.jsonp+ ‘=‘ + options.jsonpCallback;
 82 
 83      return  _sendJsonpRequest(jsonpUrl,options.jsonpCallback,options.success);
 84       
 85     }
 86     
 87      //XMLHttpRequest傳參無影響
 88     var xhr = new (window.XMLHttpRequest || ActiveXObject)(‘Microsoft.XMLHTTP‘);
 89     // get搜索字符串
 90     var search = ‘‘;
 91 
 92     // 將data序列化
 93     var param= _param(options.data)
 94 
 95     if( options.type === ‘GET‘ ) {
 96       search = (options.url.indexOf(‘?‘) > -1 ? ‘&‘ : ‘?‘) + param;
 97       if(!options.cache) {
 98         search += ‘&radom=‘+Math.random();
 99       }
100       
101       param = null;
102     }
103 
104      // ...
105   }
106 }()

首先,兼容IE創建xhr對象,XMLHttpRequest構造函數傳遞參數是無影響,然後我們定義了兩個輔助變量:searchparam,前者用於get請求的查詢字串,後者用於post請求的send內容,我們定義了一個_param方法來講對象轉換為send方法參數的模式,就如你看到的那樣,下面我們做了getpost之間合理的searchparam的賦值工作。接下來我們就可以發送請求書寫最激動人心的內容了。

最終的代碼如下

  1 ;
  2 
  3 var ajax = function () {
  4 
  5   //默認請求參數
  6   var _options = {
  7     url: null,
  8     type: ‘GET‘,
  9     data: null,
 10     dataType: ‘text‘,
 11     jsonp: ‘callback‘,
 12     jsonpCallback: ‘jsonpCallback‘,
 13     async: true,
 14     cache: true,
 15     timeout:null,
 16     contentType: ‘application/x-www-form-urlencoded‘,
 17     success: null,
 18     fail: null
 19   }
 20 
 21 
 22   // json轉化為字符串
 23   var _param = function(data) {
 24     var str = ‘‘;
 25     if( !data || _empty(data)) {
 26       return str;
 27     }
 28     for(var key in data) {
 29       str += key + ‘=‘+ data[key]+‘&‘
 30     }
 31     str = str.slice(0,-1);
 32     return str;
 33   }
 34   //判斷對象是否為空
 35   var _empty = function(obj) {
 36     for(var key in obj) {
 37       return false;
 38     }
 39     return true;
 40   }
 41 
 42   var _extend = function(target,options) {
 43     if( typeof target !== ‘object‘ || typeof options !== ‘object‘ ) {
 44       return;
 45     }
 46     var copy ,clone, name;
 47     for( name in options ) {
 48       if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
 49         target[name] = options[name];
 50       }
 51     }
 52     return target;
 53   };
 54 
 55   // 自定義text轉化json格式
 56   var parseJSON = function(text) {
 57     if(typeof text !== ‘string‘) {
 58       return;
 59     }
 60     if( JSON && JSON.parse ) {
 61       return JSON.parse(text);
 62     }
 63     return (new Function(‘return ‘+text))();
 64   }
 65 
 66   // jsonp處理函數
 67   function _sendJsonpRequest(url,callbackName,succCallback) {
 68 
 69     var script = document.createElement(‘script‘);
 70 
 71     script.type="text/javascript";
 72     script.src=url;
 73 
 74     document.body.appendChild(script);
 75     // 如果用戶自己定義了回調函數,就用自己定義的,否則,調用success函數
 76     window[callbackName] = window[callbackName] || succCallback;
 77 
 78   }
 79 
 80 
 81   return function (options) {
 82 
 83     // 沒有傳參或者沒有url,拋出錯誤
 84     if( !options || !options.url ) {
 85       throw(‘參數錯誤!‘);
 86     }
 87 
 88     // 繼承操作
 89     options.type = options.type.toUpperCase();
 90     _extend(options,_options);
 91 
 92     /*jsonp部分,直接返回*/
 93     if( options.dataType === ‘jsonp‘ ) {
 94       var jsonpUrl = options.url.indexOf(‘?‘) > -1 ? options.url: options.url +
 95         ‘?‘ + options.jsonp+ ‘=‘ + options.jsonpCallback;
 96 
 97       _sendJsonpRequest(jsonpUrl,options.jsonpCallback,options.success);
 98       
 99       return;
100     }
101 
102      //XMLHttpRequest傳參無影響
103     var xhr = new (window.XMLHttpRequest || ActiveXObject)(‘Microsoft.XMLHTTP‘);
104 
105     // get搜索字符串
106     var search = ‘‘;
107 
108     // 將data序列化
109     var param= _param(options.data)
110 
111     if( options.type === ‘GET‘ ) {
112       search = (options.url.indexOf(‘?‘) > -1 ? ‘&‘ : ‘?‘) + param;
113       if(!options.cache) {
114         search += ‘&radom=‘+Math.random();
115       }
116       
117       param = null;
118     }
119 
120     xhr.open( options.type, options.url + search, options.async );
121 
122     xhr.onreadystatechange = function() {
123       if( xhr.readyState == 4 ) {
124         if( xhr.status >= 200 && xhr.status < 300 || xhr.status == 304 ) {
125           var text = xhr.responseText;
126           // json格式轉換
127           if(options.dataType == ‘json‘) {
128               text = parseJSON(text)
129           }
130 
131           if( typeof options.success === ‘function‘) {
132 
133             options.success(text,xhr.status)
134           }
135           
136         }else {
137 
138           if(typeof options.fail === ‘function‘) {
139             options.fail(‘獲取失敗‘, 500)
140           }
141           
142         }
143       }
144     }
145 
146     xhr.setRequestHeader(‘content-type‘,options.contentType);
147     // get請求時param時null
148     xhr.send(param);
149 
150     // 如果設置了超時,就定義
151     if(typeof options.timeout === ‘number‘) {
152       // ie9+
153       if( xhr.timeout ) {
154         xhr.timeout = options.timeout;
155       }else {
156         setTimeout(function() {
157           xhr.abort();
158         },options.timeout)
159       }
160     }
161   }
162 
163 }()

可以看到,我們很熟悉的xhr代碼,在這裏,我們需要寫一個解析返回字串形成json格式對象的方法parseJSON,類似於jq中的parseJSON方法,如上所示。

我們還需要設置超時代碼,如果設置了請求超時,我們就如上定義。

註意:上面代碼中,由於懶,設置請求頭一行並沒有判斷是否在post請求下,你可以自己設置

第111天:Ajax之jQuery實現方法