溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

好程序員web前端培訓(xùn)分享JavaScript學(xué)習(xí)筆記ajax及ajax封裝

發(fā)布時(shí)間:2020-08-05 06:34:50 來(lái)源:ITPUB博客 閱讀:156 作者:好程序員 欄目:web開(kāi)發(fā)

  好程序員 web前端培訓(xùn)分享 JavaScript學(xué)習(xí)筆記ajax及ajax封裝 , ajax  全名  async javascript and XML

   是前后臺(tái)交互的能力

   也就是我們客戶端給服務(wù)端發(fā)送消息的工具,以及接受響應(yīng)的工具

   是一個(gè)  默認(rèn)異步  執(zhí)行機(jī)制的功能

   AJAX 的優(yōu)勢(shì)

00001.     不需要插件的支持,原生 js 就可以使用

00002.     用戶體驗(yàn)好(不需要刷新頁(yè)面就可以更新數(shù)據(jù))

00003.     減輕服務(wù)端和帶寬的負(fù)擔(dān)

00004.     缺點(diǎn): 搜索引擎的支持度不夠,因?yàn)閿?shù)據(jù)都不在頁(yè)面上,搜索引擎搜索不到

   AJAX 的使用

·     js 中有內(nèi)置的構(gòu)造函數(shù)來(lái)創(chuàng)建 ajax 對(duì)象

·     創(chuàng)建 ajax 對(duì)象以后,我們就使用 ajax 對(duì)象的方法去發(fā)送請(qǐng)求和接受響應(yīng)

創(chuàng)建一個(gè) ajax 對(duì)象

// IE9及以上 const   xhr   =   new   XMLHttpRequest() // IE9以下 const   xhr   =   new   ActiveXObject( 'Mricosoft.XMLHTTP' )

·  上面就是有了一個(gè) ajax 對(duì)象

·  我們就可以使用這個(gè)  xhr  對(duì)象來(lái)發(fā)送 ajax 請(qǐng)求了

配置鏈接信息

const   xhr   =   new   XMLHttpRequest() // xhr 對(duì)象中的 open 方法是來(lái)配置請(qǐng)求信息的// 第一個(gè)參數(shù)是本次請(qǐng)求的請(qǐng)求方式 get / post / put / ...// 第二個(gè)參數(shù)是本次請(qǐng)求的 url // 第三個(gè)參數(shù)是本次請(qǐng)求是否異步,默認(rèn) true 表示異步,false 表示同步// xhr.open('請(qǐng)求方式', '請(qǐng)求地址', 是否異步) xhr.open( 'get' ,   './data.php' )

·  上面的代碼執(zhí)行完畢以后,本次請(qǐng)求的基本配置信息就寫完了

發(fā)送請(qǐng)求

const   xhr   =   new   XMLHttpRequest()xhr.open( 'get' ,   './data.php' ) // 使用 xhr 對(duì)象中的 send 方法來(lái)發(fā)送請(qǐng)求 xhr.send()

·  上面代碼是把配置好信息的 ajax 對(duì)象發(fā)送到服務(wù)端

一個(gè)基本的 ajax 請(qǐng)求

·  一個(gè)最基本的 ajax 請(qǐng)求就是上面三步

·  但是光有上面的三個(gè)步驟,我們確實(shí)能把請(qǐng)求發(fā)送的到服務(wù)端

·  如果服務(wù)端正常的話,響應(yīng)也能回到客戶端

·  但是我們拿不到響應(yīng)

·  如果想拿到響應(yīng),我們有兩個(gè)前提條件

00001.  本次 HTTP 請(qǐng)求是成功的,也就是我們之前說(shuō)的 http 狀態(tài)碼為 200 ~ 299

00002.  ajax 對(duì)象也有自己的狀態(tài)碼,用來(lái)表示本次 ajax 請(qǐng)求中各個(gè)階段

ajax 狀態(tài)碼

·  ajax 狀態(tài)碼 -  xhr.readyState

·  是用來(lái)表示一個(gè) ajax 請(qǐng)求的全部過(guò)程中的某一個(gè)狀態(tài)

·  readyState === 0 表示未初始化完成,也就是  open  方法還沒(méi)有執(zhí)行

·  readyState === 1 表示配置信息已經(jīng)完成,也就是執(zhí)行完  open  之后

·  readyState === 2 表示  send  方法已經(jīng)執(zhí)行完成

·  readyState === 3 表示正在解析響應(yīng)內(nèi)容

·  readyState === 4 表示響應(yīng)內(nèi)容已經(jīng)解析完畢,可以在客戶端使用了

·  這個(gè)時(shí)候我們就會(huì)發(fā)現(xiàn),當(dāng)一個(gè) ajax 請(qǐng)求的全部過(guò)程中,只有當(dāng)  readyState === 4  的時(shí)候,我們才可以正常使用服務(wù)端給我們的數(shù)據(jù)

·  所以,配合 http 狀態(tài)碼為 200 ~ 299 

·  一個(gè) ajax 對(duì)象中有一個(gè)成員叫做  xhr.status

·  這個(gè)成員就是記錄本次請(qǐng)求的 http 狀態(tài)碼的

·  兩個(gè)條件都滿足的時(shí)候,才是本次請(qǐng)求正常完成

readyStateChange

·  ajax 對(duì)象中有一個(gè)事件,叫做  readyStateChange  事件

·  這個(gè)事件是專門用來(lái)監(jiān)聽(tīng) ajax 對(duì)象的  readyState  值改變的的行為

·  也就是說(shuō)只要  readyState  的值發(fā)生變化了,那么就會(huì)觸發(fā)該事件

·  所以我們就在這個(gè)事件中來(lái)監(jiān)聽(tīng) ajax 的  readyState  是不是到 4 了

const   xhr   =   new   XMLHttpRequest()xhr.open( 'get' ,   './data.php' ) xhr.send() xhr.onreadyStateChange   =   function   ()   {

  // 每次 readyState 改變的時(shí)候都會(huì)觸發(fā)該事件   // 我們就在這里判斷 readyState 的值是不是到 4   // 并且 http 的狀態(tài)碼是不是 200 ~ 299   if   (xhr.readyState   ===   4   &&   /^2\d{2|$/ .test(xhr.status))   {

  // 這里表示驗(yàn)證通過(guò)   // 我們就可以獲取服務(wù)端給我們響應(yīng)的內(nèi)容了    }}

responseText

·  ajax 對(duì)象中的  responseText  成員

·  就是用來(lái)記錄服務(wù)端給我們的響應(yīng)體內(nèi)容的

·  所以我們就用這個(gè)成員來(lái)獲取響應(yīng)體內(nèi)容就可以

const   xhr   =   new   XMLHttpRequest()xhr.open( 'get' ,   './data.php' ) xhr.send() xhr.onreadyStateChange   =   function   ()   {

  if   (xhr.readyState   ===   4   &&   /^2\d{2|$/ .test(xhr.status))   {

  // 我們?cè)谶@里直接打印 xhr.responseText 來(lái)查看服務(wù)端給我們返回的內(nèi)容   console.log(xhr.responseText)

   }}

使用 ajax 發(fā)送請(qǐng)求時(shí)攜帶參數(shù)

·  我們使用 ajax 發(fā)送請(qǐng)求也是可以攜帶參數(shù)的

·  參數(shù)就是和后臺(tái)交互的時(shí)候給他的一些信息

·  但是攜帶參數(shù) get 和 post 兩個(gè)方式還是有區(qū)別的

發(fā)送一個(gè)帶有參數(shù)的 get 請(qǐng)求

·  get 請(qǐng)求的參數(shù)就直接在 url 后面進(jìn)行拼接就可以

const   xhr   =   new   XMLHttpRequest() // 直接在地址后面加一個(gè) ?,然后以 key=value 的形式傳遞// 兩個(gè)數(shù)據(jù)之間以 & 分割 xhr.open( 'get' ,   './data.php?a=100&b=200' ) xhr.send()

·  這樣服務(wù)端就能接受到兩個(gè)參數(shù)

·  一個(gè)是 a,值是 100

·  一個(gè)是 b,值是 200

發(fā)送一個(gè)帶有參數(shù)的 post 請(qǐng)求

·  post 請(qǐng)求的參數(shù)是攜帶在請(qǐng)求體中的,所以不需要再 url 后面拼接

const   xhr   =   new   XMLHttpRequest()xhr.open( 'post' ,   './data.php' ) // 如果是用 ajax 對(duì)象發(fā)送 post 請(qǐng)求,必須要先設(shè)置一下請(qǐng)求頭中的 content-type// 告訴一下服務(wù)端我給你的是一個(gè)什么樣子的數(shù)據(jù)格式 xhr.setRequestHeader( 'content-type' ,   'application/x-www-form-urlencoded' ) // 請(qǐng)求體直接再 send 的時(shí)候?qū)懺?() 里面就行// 不需要問(wèn)號(hào),直接就是 'key=value&key=value' 的形式 xhr.send( 'a=100&b=200' )

·  application/x-www-form-urlencoded  表示的數(shù)據(jù)格式就是  key=value&key=value

同源策略

·  同源策略是由瀏覽器給的

·  瀏覽器不允許我們向別人發(fā)送請(qǐng)求,只能向自己的服務(wù)器發(fā)送請(qǐng)求

·  當(dāng)我們想向別人的服務(wù)器發(fā)送請(qǐng)求的時(shí)候,就會(huì)被瀏覽器阻止了

·  什么是 “別人的服務(wù)器” 呢?

·  當(dāng) 請(qǐng)求協(xié)議/域名/端口號(hào) 有任意一個(gè)不同的時(shí)候,那么就算是別人的服務(wù)器

·  這個(gè)時(shí)候就會(huì)觸發(fā)同源策略

·  我們管觸發(fā)了  同源策略  的請(qǐng)求叫做跨域請(qǐng)求

實(shí)現(xiàn)一個(gè)跨域請(qǐng)求

·  有的時(shí)候我們是需要實(shí)現(xiàn)跨域請(qǐng)求的

·  我們需要多個(gè)服務(wù)器給一個(gè)頁(yè)面提供數(shù)據(jù)

·  那么這個(gè)時(shí)候我們就要想辦法解決跨域問(wèn)題

JSONP

·  jsonp  是我們實(shí)現(xiàn)跨域請(qǐng)求的手段,是把我們之前的東西組合在一起使用的技術(shù)手段而已

·  利用的是 script 標(biāo)簽來(lái)實(shí)現(xiàn)

script 標(biāo)簽的本質(zhì)

·  瀏覽器給我們提供了一個(gè)  script  標(biāo)簽

·  它的本質(zhì)就是請(qǐng)求一個(gè)外部資源,是不受到同源策略的影響的

·  同時(shí)  script  標(biāo)簽的  src  屬性,也是一種請(qǐng)求,也能被服務(wù)器接收到

·  并且:

·  script標(biāo)簽的src屬性請(qǐng)求回來(lái)的東西是一個(gè)字符串,瀏覽器會(huì)把這個(gè)字符串當(dāng)作 js 代碼來(lái)執(zhí)行

·  所以我們就可以利用這個(gè)  script  標(biāo)簽的  src  屬性來(lái)進(jìn)行跨域請(qǐng)求了

配置代理(了解)

·  代理,分成兩種,正向代理和反向代理

正向代理

·  有一個(gè)客戶端需要向一個(gè)非同源的服務(wù)器B發(fā)送請(qǐng)求

·  我們搭建一個(gè)和客戶端同源的服務(wù)器A

·  當(dāng)客戶端發(fā)送請(qǐng)求的時(shí)候,由服務(wù)器A來(lái)接受

·  再由服務(wù)器A向服務(wù)器B發(fā)送請(qǐng)求,因?yàn)?nbsp; 同源策略是由瀏覽器給的 ,服務(wù)器之間沒(méi)有

·  服務(wù)器B接受到請(qǐng)求以后,會(huì)處理請(qǐng)求,并把響應(yīng)返回給服務(wù)器A

·  再由服務(wù)器A把響應(yīng)給到客戶端就可以了

·  我們就可以用這個(gè)方式來(lái)進(jìn)行跨域請(qǐng)求了

反向代理

·  反向代理一般是用來(lái)做負(fù)載均衡

·  當(dāng)我請(qǐng)求一個(gè)服務(wù)器的時(shí)候,其實(shí)請(qǐng)求的是服務(wù)器端設(shè)置的代理服務(wù)器

·  由代理服務(wù)器把若干大量的請(qǐng)求分發(fā)給不同的服務(wù)器進(jìn)行處理

·  再由服務(wù)器把響應(yīng)給到代理服務(wù)器

·  代理服務(wù)器返回給客戶端

封裝 AJAX

·  ajax 使用起來(lái)太麻煩,因?yàn)槊看味家獙懞芏嗟拇a

·  那么我們就封裝一個(gè) ajax 方法來(lái)讓我們使用起來(lái)簡(jiǎn)單一些

確定一下使用的方式

·  因?yàn)橛幸恍﹥?nèi)容可以不傳遞,我們可以使用默認(rèn)值,所以選擇對(duì)象傳遞參數(shù)的方式 // 使用的時(shí)候直接調(diào)用,傳遞一個(gè)對(duì)象就可以 ajax({ url: '', // 請(qǐng)求的地址 type: '', // 請(qǐng)求方式 async: '', // 是否異步 data: '', // 攜帶的參數(shù) dataType: '', // 要不要執(zhí)行 json.parse success: function () {} // 成功以后執(zhí)行的函數(shù) })

·  確定好使用方式以后,就開(kāi)始書寫封裝函數(shù)

封裝

function   ajax(options)   {

   // 先準(zhǔn)備一個(gè)默認(rèn)值    var   defInfo   =   {

     url :   '' ,   // 地址不需要默認(rèn)值      type :   'GET' ,   // 請(qǐng)求方式的默認(rèn)值是 GET      async:   false ,   // 默認(rèn)值是異步      data :   '' ,   // 參數(shù)沒(méi)有默認(rèn)值      dataType :   'string' ,   // 默認(rèn)不需要執(zhí)行 json.parse      success   ()   {},   // 默認(rèn)是一個(gè)函數(shù)    }

   // 先來(lái)判斷一下有沒(méi)有傳遞 url,如果沒(méi)有,直接拋出異常    if   ( ! options.url)   {

     throw   new   Error ( 'url 必須傳遞' )

   }

   // 有了 url 以后就,我們就把用戶傳遞的參數(shù)和我們的默認(rèn)數(shù)據(jù)合并    for   ( let   key   in   options)   {

     defInfo[key]   =   options[key]

   }

   // 接下來(lái)的一切我們都是使用我們的 defInfo 就可以了    // 第一步就是判斷參數(shù) data    // data 可以不傳遞,可以為空    // data 也可以是一個(gè) key=value&key=value 格式的字符串    // data 也可以是一個(gè)對(duì)象    // 否則就拋出異常    if   ( ! ( typeof   defInfo.data   ===   'string'   &&   /^(\w+=\w+&?)*$/ .test(defInfo.data)   ||   Object .prototype.toString.call(defInfo.data)   ===   '[object Object]' ))   {

     throw   new   Error ( '請(qǐng)按照要求傳遞參數(shù)' )

   }

   // 參數(shù)處理完畢以后,在判斷 async 的數(shù)據(jù)類型    // 只能傳遞 布爾數(shù)據(jù)類型    if   ( typeof   defInfo. async   !==   'boolean' )   {

     throw   new   Error ( 'async 參數(shù)只接受布爾數(shù)據(jù)類型' )

   }

   // 在接下來(lái)就判斷 type    // 請(qǐng)求方式我們只接受 GET 或著 POST    if   ( ! (defInfo.type.toUpperCase()   ===   'GET'   ||   defInfo.type.toUpperCase()   ===   'POST' ))   {

     throw   new   Error ( '目前本插件只接受 GET 和 POST 方式,請(qǐng)期待更新' )

   }

   // 接下來(lái)就是判斷 success 的判斷,必須是一個(gè)函數(shù)    if   ( Object .prototype.toString.call(defInfo.success)   !==   '[object Function]' )   {

     throw   new   Error ( 'success 只接受函數(shù)數(shù)據(jù)類型' )

   }

   // 參數(shù)都沒(méi)有問(wèn)題了    // 我們就要把 data 處理一下了    // 因?yàn)?data 有可能是對(duì)象,當(dāng) data 是一個(gè)對(duì)象的時(shí)候,我們要把它轉(zhuǎn)換成一個(gè)字符串    var   str   =   ''

   if   ( Object .prototype.toString.call(defInfo.data)   ===   '[object Object]' )   {

     for   ( let   attr   in   defInfo.data)   {

       str   +=   `${ attr }=${ defInfo.data[attr] }&`

     }

     str   =   str.slice( 0 ,   - 1 )

     defInfo.data   =   str

   }

   // 參數(shù)全部驗(yàn)證過(guò)了以后,我們就可以開(kāi)始進(jìn)行正常的 ajax 請(qǐng)求了    // 1. 準(zhǔn)備一個(gè) ajax 對(duì)象    //    因?yàn)橐幚砑嫒輪?wèn)題,所以我們準(zhǔn)備一個(gè)函數(shù)    function   createXHR()   {

     if   (XMLHttpRequest)   {

       return   new   XMLHttpRequest()

     }   else   {

       return   new   ActiveXObject( 'Microsoft.XMLHTTP' )

     }

   }

   // 2. 創(chuàng)建一個(gè) ajax 對(duì)象    var   xhr   =   createXHR()

   // 3. 進(jìn)行 open    xhr.open(defInfo.type,   defInfo.url   +   (defInfo.type.toUpperCase()   ===   'GET'   ?   `?${ defInfo.data }&_=${ new   Date ().getTime() }`   :   '' ),   defInfo. async )

   if   (defInfo.type.toUpperCase()   ===   'POST' )   {

     xhr.setRequestHeader( 'content-type' ,   'application/x-www-form-urlencoded' )

   }

   // 4. 進(jìn)行 send    xhr.send((defInfo.type.toUpperCase()   ===   'POST'   ?   `${ defInfo.data }`   :   '' ))

   // 5. 接受響應(yīng)    xhr.onreadystatechange   =   function   ()   {

     if   (xhr.readyState   ===   4   &&   /2\d{2}/ .test(xhr.status))   {

       // 表示成功,我們就要執(zhí)行 success        // 但是要進(jìn)行 dataType 的判斷        if   (defInfo.dataType   ===   'json' )   {

         defInfo.success(JSON.parse(xhr.responseText))

       }   else   {

         defInfo.success()

       }

     }

   }}

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI