原生JS發送非同步資料請求,js非同步

來源:互聯網
上載者:User

原生JS發送非同步資料請求,js非同步

在做項目的時候,有時候需要用到非同步資料請求,但是如果這個時候沒有架構的依賴,就需要用到原生JS進行非同步資料請求。這時候無非有兩種請求方式,一種是AJAX,另一個是JSONP。通過原生JS對非同步請求進行簡單的封裝。

AJAX

  AJAX是一種資料請求方式,不需要重新整理整個頁面就能夠更新局部頁面的資料。AJAX的技術核心是XMLHttpRequest對象,主要請求過程如下:

  • 建立XMLHttpRequest對象(new)
  • 串連伺服器(open)
  • 發送請求(send)
  • 接收響應資料(onreadystatechange)

  不說話直接貼代碼

/*** 通過JSON的方式請求* @param {[type]} params [description]* @return {[type]}  [description]*/ajaxJSON(params) { params.type = (params.type || 'GET').toUpperCase(); params.data = params.data || {}; var formatedParams = this.formateParams(params.data, params.cache); var xhr; //建立XMLHttpRequest對象 if (window.XMLHttpRequest) {  //非IE6  xhr = new XMLHttpRequest(); } else {  xhr = new ActiveXObject('Microsoft.XMLHTTP'); } //非同步狀態發生改變,接收響應資料 xhr.onreadystatechange = function() {  if (xhr.readyState == 4 && xhr.status == 200) {   if (!!params.success) {    if (typeof xhr.responseText == 'string') {     params.success(JSON.parse(xhr.responseText));    } else {     params.success(xhr.responseText);    }   }  } else {   params.error && params.error(status);  } } if (params.type == 'GET') {  //串連伺服器  xhr.open('GET', (!!formatedParams ? params.url + '?' + formatedParams : params.url), true);  //發送請求  xhr.send(); } else {  //串連伺服器  xhr.open('POST', params.url, true);  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');  //發送請求  xhr.send(formatedParams); }},/*** 格式化資料* @param {Obj}  data 需要格式化的資料* @param {Boolean} isCache 是否加入隨機參數* @return {String}   返回的字串*/formateParams: function(data, isCache) { var arr = []; for (var name in data) {  arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name])); } if (isCache) {  arr.push('v=' + (new Date()).getTime()); } return arr.join('&');}

  IE7及其以上版本中支援原生的 XHR 對象,因此可以直接用:var oAjax = new XMLHttpRequest();。IE6及其之前的版本中,XHR對象是通過MSXML庫中的一個ActiveXObject對象實現的。

  通過xhr的open函數來串連伺服器,主要接收三個參數:請求方式、請求地址和是否非同步請求(一般都是非同步請求)。請求方式有兩種,GET和POST,GET是通過URL將資料提交到伺服器的,POST則是通過將資料作為send方法的參數發送到伺服器。

  給xhr綁定狀態改變函數onreadystatechange,主要用來檢測xhr的readyState的變化,當非同步發送成功後,readyState的數值會由0變成4,同時觸發onreadystatechange事件。readyState的屬性及對應狀態如下:

0 (未初始化) 對象已建立,但是尚未初始化(尚未調用open方法)
1 (初始化) 對象已建立,尚未調用send方法
2 (發送資料) send方法已調用,但是當前的狀態及http頭未知
3 (資料傳送中) 已接收部分資料,因為響應及http頭不全,這時通過responseBody和responseText擷取部分資料會出現錯誤
4 (完成) 資料接收完畢,此時可以通過通過responseBody和responseText擷取完整的回應資料

  在readystatechange事件中,先判斷響應是否接收完成,然後判斷伺服器是否成功處理請求,xhr.status 是狀態代碼,狀態代碼以2開頭的都是成功,304表示從緩衝中擷取,上面的代碼在每次請求的時候都加入了隨機數,所以不會從緩衝中取值,故該狀態不需判斷。

JSONP

  如果還是用上面的XMLHttpRequest對象來發送需要跨域的請求,雖然調用了send函數,但是xhr的狀態一直都是0,也不會觸發onreadystatechange事件,這個時候就要用到JSONP的請求方式了。

  JSONP(JSON with Padding) 是一種跨域請求方式。主要原理是利用了script標籤可以跨域請求的特點,由其src屬性發送請求到伺服器,伺服器返回js代碼,網頁端接受響應,然後就直接執行了,這和通過script標籤引用外部檔案的原理是一樣的。

  JSONP由兩部分組成:回呼函數和資料,回呼函數一般是由網頁端控制,作為參數發往伺服器端,伺服器端把該函數和資料拼成字串返回。

  比如網頁端建立一個script標籤,並給其src賦值為http://www.test.com/json/?callback=process, 此時網頁端就發起一個請求。服務端將要返回的資料拼作為函數的參數傳入,服務端返回的資料格式類似”process({‘name:'xieyufei'})”,網頁端接收到了響應值,因為要求者是 script,所以相當於直接調用process方法,並且傳入了一個參數。

  不說話直接貼代碼。

/*** 通過JSONP的方式請求* @param {[type]} params [description]* @return {[type]}  [description]*/ajaxJSONP(params) { params.data = params.data || {}; params.jsonp = params.jsonp || 'callback'; // 設定傳遞給背景回調參數名和參數值 var callbackName = 'jsonp_' + (new Date()).getTime(); params.data[params.jsonp] = callbackName; var formatedParams = this.formateParams(params.data, params.cache); //建立script標籤並插入到頁面中 var head = document.getElementsByTagName('head')[0]; var script = document.createElement('script'); head.appendChild(script); //建立jsonp回呼函數  window[callbackName] = function(json) {  head.removeChild(script);  clearTimeout(script.timer);  window[callbackName] = null;  params.success && params.success(json); }; //發送請求  script.src = (!!formatedParams ? params.url + '?' + formatedParams : params.url); //為了得知此次請求是否成功,設定逾時處理 if (params.time) {  script.timer = setTimeout(function() {   window[callbackName] = null;   head.removeChild(script);   params.error && params.error({    message: '逾時'   });  }, params.time); }}

  給script標籤設定src屬性時瀏覽器就會去發送請求,但是只能發送一次請求,導致script標籤不能複用,因此每次操作完都需要把script標籤移除。在瀏覽器發送請求之前給全域綁定一個回呼函數,當資料請求成功時就會調用這個回呼函數。

總結

  將兩種發送非同步資料的方式整合起來,根據dataType來進行判斷選用哪種方式。貼上完整的代碼

var xyfAjax = { ajax: function(params) {  params = params || {};  params.cache = params.cache || false;  if (!params.url) {   throw new Error('參數不合法');  }  params.dataType = (params.dataType || 'json').toLowerCase();  if (params.dataType == 'jsonp') {   this.ajaxJSONP(params);  } else if (params.dataType == 'json') {   this.ajaxJSON(params);  } }, /** * 通過JSONP的方式請求 * @param {[type]} params [description] * @return {[type]}  [description] */ ajaxJSONP(params) {  params.data = params.data || {};  params.jsonp = params.jsonp || 'callback';  // 設定傳遞給背景回調參數名和參數值  var callbackName = 'jsonp_' + (new Date()).getTime();  params.data[params.jsonp] = callbackName;  var formatedParams = this.formateParams(params.data, params.cache);  //建立script標籤並插入到頁面中  var head = document.getElementsByTagName('head')[0];  var script = document.createElement('script');  head.appendChild(script);  //建立jsonp回呼函數   window[callbackName] = function(json) {   head.removeChild(script);   clearTimeout(script.timer);   window[callbackName] = null;   params.success && params.success(json);  };  //發送請求   script.src = (!!formatedParams ? params.url + '?' + formatedParams : params.url);  //為了得知此次請求是否成功,設定逾時處理  if (params.time) {   script.timer = setTimeout(function() {    window[callbackName] = null;    head.removeChild(script);    params.error && params.error({     message: '逾時'    });   }, params.time);  } }, /** * 通過JSON的方式請求 * @param {[type]} params [description] * @return {[type]}  [description] */ ajaxJSON(params) {  params.type = (params.type || 'GET').toUpperCase();  params.data = params.data || {};  var formatedParams = this.formateParams(params.data, params.cache);  var xhr;  //建立XMLHttpRequest對象  if (window.XMLHttpRequest) {   //非IE6   xhr = new XMLHttpRequest();  } else {   xhr = new ActiveXObject('Microsoft.XMLHTTP');  }  //非同步狀態發生改變,接收響應資料  xhr.onreadystatechange = function() {   if (xhr.readyState == 4 && xhr.status == 200) {    if (!!params.success) {     if (typeof xhr.responseText == 'string') {      params.success(JSON.parse(xhr.responseText));     } else {      params.success(xhr.responseText);     }    }   } else {    params.error && params.error(status);   }  }  if (params.type == 'GET') {   //串連伺服器   xhr.open('GET', (!!formatedParams ? params.url + '?' + formatedParams : params.url), true);   //發送請求   xhr.send(null);  } else {   //串連伺服器   xhr.open('POST', params.url, true);   xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');   //發送請求   xhr.send(formatedParams);  } }, /** * 格式化資料 * @param {Obj}  data 需要格式化的資料 * @param {Boolean} isCache 是否加入隨機參數 * @return {String}   返回的字串 */ formateParams: function(data, isCache) {  var arr = [];  for (var name in data) {   arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));  }  if (isCache) {   arr.push('v=' + (new Date()).getTime());  }  return arr.join('&'); }}xyfAjax.ajax({ url:'http://www.xieyufei.com', type:'get', //or post dataType:'json', //or jsonp data:{  name:'xyf' }, success: function(data){  console.log(data) }})

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援幫客之家。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.