首頁  >  文章  >  web前端  >  原生JS發送非同步資料請求實例詳解

原生JS發送非同步資料請求實例詳解

零下一度
零下一度原創
2017-06-17 17:24:491426瀏覽

這篇文章主要為大家詳細介紹了原生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)
 }
})

以上是原生JS發送非同步資料請求實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn