AJAX

如何發(fā)請求?

  • 用form可以發(fā)post或get請求,但是但是會刷新頁面或新開頁面
  • 用 a 可以發(fā) get 請求,但是也會刷新頁面或新開頁面
  • 用 img 可以發(fā) get 請求,但是只能以圖片的形式展示
  • 用 link 可以發(fā) get 請求,但是只能以 CSS、favicon 的形式展示
  • 用 script 可以發(fā) get 請求,但是只能以腳本的形式運行

所以急需一種API可以滿足以下兩個要求:

  1. get、post、put、delete 請求都行
  2. 想以什么形式展示就以什么形式展示

微軟的突破

IE 5 率先在 JS 中引入 ActiveX 對象(API),使得 JS 可以直接發(fā)起 HTTP 請求。隨后 Mozilla、 Safari、 Opera 也跟進了,取名 XMLHttpRequest,并被納入 W3C 規(guī)范。
1.png

AJAX

  • Jesse James Garrett 將如下技術(shù)取名叫做 AJAX(Async JavaScript And XML):異步的 JavaScript 和 XML
  1. 使用 XMLHttpRequest 發(fā)請求
  2. 服務(wù)器返回 XML 格式的字符串(現(xiàn)在都使用JSON來代替XML)
  3. JS 解析 XML,并更新局部頁面
  • AJAX就是用JS去發(fā)請求
  • 響應的第四部分是字符串,可以用 JSON 語法表示一個對象,也可以用 JSON 語法表示一個數(shù)組,還可以用 XML 語法,還可以用 HTML 語法,還可以用 CSS 語法,還可以用 JS 語法,還可以用自創(chuàng)的語法
  • 示例
myButton.addEventListener('click',(e)=>{
  let request = new XMLHttpRequest()
  request.open('get','/xxx')//配置request
  request.send()
  setInterval(()=>{console.log(request.readyState)},1)
})

結(jié)果:
2.png

XMLHttpRequest.readyState 屬性返回一個 XMLHttpRequest 代理當前所處的狀態(tài)


3.png

圖2中沒有出現(xiàn)0、2、3是因為他們運行太快,沒有捕捉到;每一次都會按照0~4的狀態(tài)來運行。
由此可見,每毫秒來捕捉也無法得到所有的狀態(tài),那么有沒有一個屬性只要狀態(tài)發(fā)生變化就通知我?有的。
request.onreadystatechange 

如何使用 XMLHttpRequest

myButton.addEventListener('click',(e)=>{
  let request = new XMLHttpRequest()
  request.open('get','/xxx')//配置request
  request.send()
  request.onreadystatechange = ()=>{
    if(request.readyState === 4){
      console.log('請求響應完畢了')
      if(request.status >= 200 && request.status < 300){
        console.log('說明請求成功')
        console.log(request.responseText)
        let string = request.responseText
        let object = window.JSON.parse(string)
        //把符合JSON語法的字符串轉(zhuǎn)換成JS對應的值,JSON.parse是瀏覽器提供的
        console.log(typeof object)
        console.log(object)
      }
    }
  }
})
//后端代碼
else if(path==='/xxx'){
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/json;charset=utf-8')
    response.setHeader('Access-Control-Allow-Origin', 'http://frank.com:8001')
    response.write(`
    {
      "note":{
        "to": "小谷",
        "from": "方方",
        "heading": "打招呼",
        "content": "hi"
      }
    }
    `)
    response.end()
  }

原生JS寫一個AJAX

let request = new XMLHttpRequest()//聲明
  request.open('get','/xxx')//配置request
  request.send()//發(fā)送
  request.onreadystatechange = ()=>{
    if(request.readyState === 4){
      if(request.status >= 200 && request.status < 300){
        let string = request.responseText
        let object = window.JSON.parse(string)//解析
      }
    }
  }

JSON

  1. JSON是由Douglas Crockford(道格拉斯克羅克福德)構(gòu)想設(shè)計的數(shù)據(jù)交換語言,它是一門新的語言,與JavaScript不一樣
  2. JS VS JSON
    4.png

同源策略

  • 即只有 協(xié)議+端口+域名 一模一樣才允許發(fā) AJAX 請求,否則瀏覽器上的任何網(wǎng)頁都可被隨意盜取信息
  1. http://baidu.com 可以向 http://www.baidu.com 發(fā) AJAX 請求嗎? 不可以
  2. http://baidu.com:80 可以向 http://baidu.com:81 發(fā) AJAX 請求嗎? 不可以
    要保持一模一樣才能發(fā)AJAX請求
  • 如果想要請求別的域名,那么就給它的后臺打電話,通過兩種方式處理①JSONP(但它不能發(fā)POST請求);②CORS跨域;(用哪種方法都可以)

CORS跨域

  • Cross-Origin Resource Sharing(跨站資源共享)
  • 只需在需要共享的那個域名下加上一句代碼
    response.setHeader('Access-Control-Allow-Origin', 'http://frank.com:8001')

就是告訴瀏覽器http://frank.com:8001這個網(wǎng)站是我的朋友,你不要攔它,可以讓它讀我的內(nèi)容

AJAX的所有功能

  • 客戶端的JS發(fā)起請求(瀏覽器上的)
  • 服務(wù)端的JS發(fā)送響應(Node.js上的)
  1. JS 可以設(shè)置任意請求 header
    第一部分 request.open('get', '/xxx') //瀏覽器默認get請求是不顯示第四部分的
    第二部分 request.setRequestHeader('Content-Type','x-www-form-urlencoded')
    第四部分 request.send('a=1&b=2') //請求體
  2. JS 可以獲取任意響應 header
    第一部分 request.status //狀態(tài)碼
    request.statusText //狀態(tài)碼的文字解釋
    第二部分 request.getResponseHeader('Content-Type') //獲取指定的響應頭
    request.getAllResponseHeaders() //獲取全部的響應頭
    第四部分 request.responseText //響應體
    至此,HTTP是如何請求響應的,就大致了解了:
    ①客戶端通過AJAX設(shè)置請求頭,發(fā)送請求到服務(wù)器端(服務(wù)器端需要指定端口)
    ②服務(wù)器端設(shè)置響應并發(fā)送到客戶端(客戶端不需要指定端口)

用jQuery封裝AJAX

window.jQuery = function(nodeOrSelector){
  let nodes = {}
  nodes.addClass = function(){}
  return nodes
}
window.jQuery.ajax = function(url,method,body,success,fail){
  let request = new XMLHttpRequest()
  request.open(method,url)//配置request
  request.onreadystatechange = ()=>{
    if(request.readyState === 4){
      if(request.status >= 200 && request.status < 300){
       success.call(undefined,request.responseText)
      }else if(request.status >= 400){
        fail.call(undefined,request)
      }
    }
  }
  request.send(body)
}

window.$ = window.jQuery

myButton.addEventListener('click',(e)=>{
  window.jQuery.ajax(
   '/xxx',
   'post',
   'a=1&&b=2',
   ()=>{console.log(1)},
   ()=>{console.log(2)}
  )
})

但是上面最大的不足就是ajax函數(shù)中參數(shù)太多,容易造成忘記每個參數(shù)代表什么,所以需要作出優(yōu)化,把所有參數(shù)轉(zhuǎn)換成一個對象傳進去

window.jQuery.ajax = function(options){
  
  let url = options.url
  let method = options.method
  let body = options.body
  let success = options.success
  let fail = options.fail
  let headers = options.headers
......
}

利用ES6的解構(gòu)賦值語法優(yōu)化參數(shù)

window.jQuery.ajax = function(options){
  let {url,method,body,success,fail,headers} = options
......
}

繼續(xù)優(yōu)化

window.jQuery.ajax = function({url,method,body,success,fail,headers}){
......
}

Promise

  • 因為成功需要回調(diào)成功函數(shù),失敗要回調(diào)失敗函數(shù),但是每個庫的成功失敗回調(diào)函數(shù)名是不一樣的,例如image.onload(成功),image.onerror(失?。?,我們不可能一一地去查每個庫回調(diào)函數(shù)的名字,所以就引入promise(promise是window下的全局屬性),利用promise的then屬性。
then(()=>{},()=>{}) //成功執(zhí)行第一個函數(shù),失敗執(zhí)行第二個函數(shù)
  • 利用jQuery的promise屬性(不要忘記引入jQuery)
myButton.addEventListener('click',(e)=>{
  $.ajax(
   {url:'/xxx',
   method:'post',
   headers:{
     'Content-Type':'x-www-form-urlencoded',
     'doudou':'18'
    }   
   }).then(
     (text)=>{console.log(text)},
     (request)=>{console.log(request)}
    )
})
  • 自己定義promise來封裝AJAX
window.jQuery = function(nodeOrSelector){
  let nodes = {}
  nodes.addClass = function(){}
  nodes.html = function(){}
  return nodes
}
window.$ = window.jQuery
window.Promise = function(fn){
  return {
    then: function(){}
  }
}

window.jQuery.ajax = function({url,method,body,headers}){
  return new Promise(function(resolve, reject){ //這六個單詞是最重要的
    let request = new XMLHttpRequest()
    request.open(method,url)//配置request
    for(let key in headers){ //遍歷對象中的屬性
      let value = headers[key]
      request.setRequestHeader(key,value)
    }
    request.onreadystatechange = ()=>{
      if(request.readyState === 4){
        if(request.status >= 200 && request.status < 300){
         resolve.call(undefined,request.responseText)
        }else if(request.status >= 400){
          reject.call(undefined,request)
        }
      }
    }
    request.send(body)
  })

}
myButton.addEventListener('click',(e)=>{
  let promise = window.jQuery.ajax(
   {url:'/xxx',
   method:'post',
   headers:{
     'Content-Type':'x-www-form-urlencoded',
     'doudou':'18'
    }   
   })
   promise.then(
     (text)=>{console.log(text)},
     (request)=>{console.log(request)}
    )
})
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容