AJAX 的前因後果

簡要理解 AJAX

  1. 你才返回對象,你全家都返回對象("你"指的是響應內容的第四部分)
  2. JS 是一門語言,JSON 是另外一門語言,JSON 這門語言抄襲了 JS這門語言
  3. AJAX 就是用 JS set 請求和get 響應
  4. 響應的第四部分是字符串,能夠用 JSON 語法表示一個對象,也能夠用 JSON 語法表示一個數組,還能夠用 XML 語法,還能夠用 HTML 語法,還能夠用 CSS 語法,還能夠用 JS 語法,還能夠用我自創的語法

如何發請求?

用 form 能夠發請求,可是會刷新頁面或新開頁面
用 a 能夠發 get 請求,可是也會刷新頁面或新開頁面
用 img 能夠發 get 請求,可是隻能以圖片的形式展現
用 link 能夠發 get 請求,可是隻能以 CSS、favicon 的形式展現
用 script 能夠發 get 請求,可是隻能以腳本的形式運行(就是 JSONP 的實現原理)前端

有沒有什麼方式能夠實現node

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

微軟的突破

IE 5 率先在 JS 中引入 ActiveX 對象(API),使得 JS 能夠直接發起 HTTP 請求。
隨後 Mozilla、 Safari、 Opera 也跟進(抄襲)了,取名 XMLHttpRequest,並被歸入 W3C 規範git

AJAX

Jesse James Garrett 講以下技術取名叫作 AJAX:異步的 JavaScript 和 XML程序員

AJAX 技術包括如下四步:github

  1. 建立 AJAX 對象, 即 XMLHttpRequest
  2. 使用 XMLHttpRequest 發請求
  3. 服務器返回 XML 格式的字符串
  4. JS 解析 XML,並更新局部頁面

AJAX demo

https://github.com/wojiaofeng...ajax

理解 AJAX

學 AJAX 以前,須要知道 HTTP 請求內容和 HTTP 響應內容的四個部分,以下chrome

問題: 老師的 key: alue有許多---的是須要背的嗎?

請求內容:json

請求內容

響應內容: 後端

響應內容

同時還要知道怎麼在 Chrome 上查看 HTTP request 和 HTTP response 跨域

選區_112.png

那麼,AJAX 是什麼呢?咱們能夠畫出 」 client 和 server 「 的關係圖:

選區_113.png

AJAX 就是在 chrome 經過 XMLHttpRequest 對象, 構造(set)HTTP 請求和獲取(get)HTTP 響應的技術

那麼 AJAX 的具體實現方法是怎麼樣的呢?

  1. JS 設置(set)任意請求 header
    請求內容第一部分 request.open('get', '/xxx')
    請求內容第二部分 request.setRequestHeader('content-type','x-www-form-urlencoded')
    請求內容第四部分 request.send('a=1&b=2')
  2. JS 獲取(get)任意響應 header
    響應內容第一部分 request.status / request.statusText
    響應內容第二部分 request.getResponseHeader() / request.getAllResponseHeaders()
    響應內容第四部分 request.responseText

jQuery 的 AJAX 實現代碼迭代過程

如何肯定寫的 AJAX 代碼是否正確?將你寫的代碼放到 AJAX demo 的 main.js

初版:使用原生 js 中的 XMLHttpRequest 實現 ajax

//本身寫的初版
myButton.addEventListener('click', function(){
  ajax()
})

function ajax(){
//至關於告訴瀏覽器我要set Http 請求了
  var request = new XMLHttpRequest()
//對應 http 請求的第一部分
  request.open("post", "/xxx")
//對應 http 請求的第二部分
  request.setRequestHeader("name", "rjj")
  request.setRequestHeader("name", "zzz")
//對應 http 請求的第三部分,僅僅是爲了便於記憶
  request.onreadystatechange = function(){
    if(request.readyState === 4){
      if(request.status >= 200 && request.status < 300){
        console.log("成功")
        console.log("request.responseText")
        console.log(request.responseText)
      }else{
        console.log("失敗")
        console.log(request)
      }
    }
  }
//對應 http 請求的第四部分
  request.send("xxxxxxxxx")
}

第二版:放到函數內

把初版中的function ajax(){}內寫死的內容提取出來, 用變量獲取, 代碼以下:

//本身寫的第二版
myButton.addEventListener('click', function(){
  ajax("post", "/xxx", {name:'rjj', sss:'zxxx'}, fffff, yyyyyy)
})

function ajax(method, path, header, successFn, failFn, body){
  var request = new XMLHttpRequest()

  request.open(method, path)

  for(var key in header){
    request.setRequestHeader(key, header[key])
  }

  request.onreadystatechange = function(){
    if(request.readyState === 4){
      if(request.status >= 200 && request.status < 300){
          //調用 ajax 函數的成功函數,而且往這個函數添加 request.responseText 變量做爲第一個參數
        successFn.call(undefined, request.responseText)
      }else{
        failFn.call(undefined, request)
      }
    }
  }

  request.send(body)
}

function fffff(x){
  console.log(x)
  console.log("請求成功了")
}

function yyyyyy(x){
  console.log(x)
  console.log("請求失敗了了")

}

第三版:更靈活的函數調用

第二版的函數調用實在太難用了, 根本不能在實際中使用, 我能不能改進一下?

我能不能像這樣調用函數? 注意我能夠改變每一個 key: value 的位置, 還能夠不設置某個 key: value

ajax({
  method: "post",
  path: "/xxx",
  header:{
    name:"rjj",
    test:"rjj111",
    test2:"rjj2222"
  }
  body: "password=xxx",
  successFn: success,
  failFn: fail
})
myButton.addEventListener('click', function(){
  ajax({
    method: "post",
    header:{
      name: "xxx",
      zzz:'xxx',
    },
    successFnAA: function(x){
      console.log(x)
    },
    failFnAA: function(x){
      console.log(x)
    },
    path: "/xxx",
  })
})

function ajax(options){

  var method = options.method
  var path = options.path
  var header = options.header
  var successFn = options.successFnAA
  var failFn = options.failFnAA
  var body = options.body

  var request = new XMLHttpRequest()

  request.open(method, path)

  for(var key in header){
    request.setRequestHeader(key, header[key])
  }

  request.onreadystatechange = function(){
    if(request.readyState === 4){
      if(request.status >= 200 && request.status < 300){
        successFn.call(undefined, request.responseText)
      }else{
        failFn.call(undefined, request)
      }
    }
  }

  request.send(body)
}

注意:

  1. successFnAA 是參數, 參數的值是一個函數, 函數的內容是function(x){console.log(x)}
  2. 可是這個函數AA沒有執行, 他是在 ajax 函數內部執行, 而且往函數AA添加了一個參數(request.responseText)
  3. 函數AA叫作 callback 函數

第四版: 把他放到自制的 jQuery 上

我想把原生的 AJAX 實現代碼封裝到我本身寫的庫,應該怎麼辦?

創造一個對象, 把第三版的 AJAX 函數掛到這個對象上便可

myButton.addEventListener("click", function(){
$.ajax(
  {
    method: "post",
    path: "/xxx",
    header:{
      name: "xxx",
      zzz:'xxx',
    },
    successFnAA: function(x){
      console.log(x)
    },
    failFnAA: function(x){
      console.log(x)
  } 
})
})

//創造對象
window.jQuery = function(nodeOrSelector){
  var nodes = {}
  return nodes
}

//將 AJAX 函數掛到對象上
window.jQuery.ajax = function(options){

  var method = options.method
  var path = options.path
  var header = options.header
  var successFn = options.successFnAA
  var failFn = options.failFnAA
  var body = options.body

  var request = new XMLHttpRequest()

  request.open(method, path)

  for(var key in header){
    request.setRequestHeader(key, header[key])
  }

  request.onreadystatechange = function(){
    if(request.readyState === 4){
      if(request.status >= 200 && request.status < 300){
        successFn.call(undefined, request.responseText)
      }else{
        failFn.call(undefined, request)
      }
    }
  }

  request.send(body)
}

//僅僅是簡寫,並不重要
window.$ = window.jQuery

第五版: 使用 ES6 將代碼優化(析構賦值)

  1. 原代碼:

    var method = options.method
    var path = options.path
    var header = options.header
    var successFn = options.successFn
    var failFn = options.failFn
    var body = options.body
  2. 使用 ES6 代碼優化:

    let {method, path, header, successFn, failFn, body} = options
  3. 再次優化:

    將上一步的代碼刪除, 複製{method, path, header, successFn, failFn, body}

    放到window.jQuery.ajax = function(AAA){}的AAA處

第六版: 使用 promise 統一成功函數名和失敗函數名

若是一個項目須要使用兩個不一樣的庫,那麼你就必須去看這個庫的代碼才能知道如何調用成功函數和失敗函數, 因此咱們使用 promise 來統一函數名,調用這個庫的時候就沒必要考慮成功函數的名字

記住: return new Promise(function(resolve, reject){})

添加 promise 步驟

  1. 在 window.jQuery.ajax 函數內部, 剪切全部代碼
  2. 在 window.jQuery.ajax 函數內部,添加return new Promise(function(resolve, reject){AAA})
  3. 在AAA區域複製代碼
  4. 將 successFn 變成 resolve, 將 failFn 變成 reject

使用 promise

  1. 將調用 jQuery.ajax 中的 successFnAA 和 failFn 及其參數內容刪除
  2. jQuery.ajax()以後添加.then,其中第一個參數表示成功函數, 第二個參數表是失敗函數
myButton.addEventListener("click", function() {
    jQuery.ajax({
        method: "post",
        path: "/xxx",
        header: {
            name: "xxx",
            zzz: 'xxx'
        }
    }).then(function () {
        console.log(1)
    }, function () {
        console.log(2)
    })


})


window.jQuery = function(nodeOrSelector){
    var nodes = {}
    return nodes
}



window.jQuery.ajax = function(options){
    return new Promise(function (resolve, reject) {

        var method = options.method
        var path = options.path
        var header = options.header
        var body = options.body

        var request = new XMLHttpRequest()

        request.open(method, path)

        for (var key in header) {
            request.setRequestHeader(key, header[key])
        }

        request.onreadystatechange = function(){
            if (request.readyState === 4) {
                if (request.status >= 200 && request.status < 300) {
                    resolve.call(undefined, request.responseText)
                } else {
                    reject.call(undefined, request)
                }
            }
        }
        request.send(body)
    })
}

JSON —— 一門新語言

http://json.org

同源策略

只有 協議+端口+域名 如出一轍才容許發 AJAX 請求

如出一轍如出一轍如出一轍如出一轍如出一轍如出一轍如出一轍如出一轍

  1. http://baidu.com 能夠向 http://www.baidu.com 發 AJAX 請求嗎 no
  2. http://baidu.com:80 能夠向 http://baidu.com:81 發 AJAX 請求嗎 no

瀏覽器必須保證
只有 協議+端口+域名 如出一轍才容許發 AJAX 請求
CORS 能夠告訴瀏覽器,我倆一家的,別阻止他

突破同源策略 === 跨域

Cross-Origin Resource Sharing
C O 資源R S

CORS 跨域

A網站的前端程序員打電話告訴B網站的後端程序員

A前: 我想和你的網站進行交互, 你贊成嗎?

B後: 我贊成

而後B後端程序員就在後臺代碼(響應內容)寫上這一句代碼:

response.setHeader("Access-Control-Allow-Origin", "http://A.com:8001"), 網站是A網站的前端程序員告訴給B後端

這就是 CORS 跨域

個人 github 博客地址: https://github.com/wojiaofeng...以爲好的能夠 start ,O(∩_∩)O謝謝

相關文章
相關標籤/搜索