1. 程式人生 > >2018-9-9-03關於ajax(這好像是第三次總結了)

2018-9-9-03關於ajax(這好像是第三次總結了)

  • 什麼是ajax(前後端分離和不分離的優勢弊端)

 

        ajax基礎知識
            什麼是ajax?
            async javascript and xml ,非同步的js和xml
        xml:可擴充套件的標記語言
            作用是用來儲存資料的(通過自己的擴充套件的標記名稱清晰的展示出資料結構)

            ajax之所以稱之為一步的js和xml,主要原因是:當初最開始使用ajax
            實現客戶端和伺服器端資料通訊的時候,傳輸的資料格式一般都是xml格式的資料
            ,所以稱之為非同步js和xml(現在一般都是基於json格式來進行資料傳輸的)

        非同步的js
            這裡的非同步不是說ajax只能基於非同步進行請求(雖然建議都使用非同步程式設計),
            這裡的非同步特指的是“區域性重新整理”

            區域性重新整理vs全域性重新整理
            在非完全前後端分離專案中,前端開發只需要完成頁面的製作,並且把一些基礎的人機互動效果
            ,使用js完成即可,頁面中需要動態呈現內容的部分,都是交給後臺開發工程師做資料繫結和基於
            伺服器進行渲染的    
            【優勢】
            1.動態展示的資料在頁面的原始碼中可以看見,有利於SEO優化推廣(有利於搜尋引擎的收錄和抓取)
            2.從伺服器端獲取的結果就是最後要呈現的結果了,不需要客戶端做額外的事情,所以頁面載入速度快(
            前提是伺服器端處理的速度夠快)
            【弊端】
            1.如果頁面存在需要實時更新的資料,每次想要展示最新的資料,
            頁面都需要重新的重新整理一次
            2.都交給伺服器端做資料渲染,伺服器端的壓力太大,如果伺服器處理不過來,頁面呈現的速度更慢
            3.這種模式不利於開發(開發效率低)

            目前市場上大部分專案都是前後端完全分離的專案
                前後端完全分離的專案,頁面中需要動態繫結的資料是交給客戶端完成渲染的
                1.向伺服器傳送ajax請求
                2.把從伺服器端獲取的資料解析處理,拼接成為我麼需要的html字串
                3.把拼接好的字串替換頁面中某一部分的內容(區域性重新整理),頁面整體不需要重新載入
                區域性渲染即可
            【優勢】
            1.我們可以根據需求任意修改頁面中某一部分的內容(例如實時重新整理),整體頁面不重新整理,效能好,體驗好
            (所有表單驗證,需要實時重新整理的等需求都要基於ajax實現)
            2.有利於開發,提高開發效率
                前後端完全分離,後臺不需要考慮前端如何實現,前端也不需要考慮後端用什麼技術,真正意義上實現了技術的劃分
                可以同時開發:專案開發開始,首先指定前後端資料互動的文件介面(文件中包涵了調取哪個介面或者哪些資料等協議規範)
                後臺先把介面寫好(目前很多公司也需要前端自己拿node來模擬這些介面),客戶端按照介面調取即可,後臺在此去實現介面功能即可

            【弊端】
            1.不利於SEO優化:第一次從伺服器端獲取的內容各種不好喊需要動態繫結的資料,所以頁面的原始碼中沒有這些內容,
            不利於SEO收錄,後期通過js新增到頁面中的內容,並不會解除安裝頁面的原始碼中(是原始碼不是頁面結構)
            2.交由客戶端渲染,首先需要把頁面呈現,然後再通過js的非同步ajax請求獲取資料,然後資料繫結,瀏覽器再把動態增加的
            部分重新渲染,無形中浪費了一些時間,沒有伺服器段渲染頁面呈現速度
  • GET請求和POST請求的區別

        基於原生js實現ajax

        1.let xhr=new XMLHttpRequest()
            //不相容IE6及更低版本的瀏覽器(ie6:ActiveXObject)
        2.xhr.open([method],[url],[async],[user name],[user password]) 
            //開啟請求地址(可以理解成一些基礎配置,但並沒有傳送請求)
        3.xhr.onreadystatechange=function(){
            //監聽AJAX狀態改變,獲取響應資訊(獲取響應頭資訊,獲取響應主體資訊)
            if(xhr.readyState===4&&xhr.status===200){
                let result=xhr.responseText; //獲取響應主體中的內容
            }
        }
        
        4.xhr.send(null)
            //傳送ajax請求(括號中傳遞的內容就是請求主體的內容)




        xhr.open([method],[url],[async],[user name],[user password])
        [AJAX請求方式]
        1.GET請求系列
            get:
            delet://從伺服器上刪除某些資原始檔
            head:只想獲取伺服器返回的響應頭資訊(響應主體的內容不需要獲取)
            ...
        2.POST請求系列
            post:
            put://向伺服器中增加指定的資原始檔
            ...
            
            

          不管哪一種請求方式,客戶端都可以把資訊傳遞給伺服器,伺服器也可以把資訊返回給客戶端
          只是GET系列一般以獲取為主(給的少,拿回來的多),而post系列一般以同送為主(給的多,拿回來的少)
          1.如果想獲取一些動態展示的資訊,一般使用get請求,因為只需要向伺服器傳送請求,告訴伺服器想要什麼
          ,服務端就會把需要的資料返回
          2.在實現註冊功能的時候,我們需要把客戶輸入的資訊傳送給伺服器進行儲存,伺服器一般返回成功還是失敗等狀態
          此時一般基於POST請求完成

          GET系列請求和POST系列請求,在專案實戰中存在很多的區別
          1.GET請求傳遞給伺服器的內容一般沒有POST請求傳遞給伺服器的內容多
          原因:GET請求傳遞給伺服器的內容一般都是基於url地址問號傳遞引數來實現的,而post請求一般都是基於
          設定請求主體來實現的,各大瀏覽器都有自己的URL最大限制(谷歌:8kb,火狐:7kb,ie:2kb...)
          超過長度的部分,瀏覽器會自動擷取掉,導致傳遞給伺服器資料丟失。
          理論上post請求通過請求主體傳遞是沒有大小限制的,真實專案中為了保證傳輸的速率,我們也會限制大小(例如:上傳的資料或者
          圖片我們會做大小的限制)
          2.GET請求很容易出現快取(這個快取不可控:一般都不需要),而post不會出現快取(除非自己特殊處理)
          3.GET請求沒有post請求安全(post也並不是十分安全,只是相對安全)


          url:請求資料的地址(API地址),後臺開發工程師會編寫一個api文件,在api文件中彙總了一些哪些資料需要使用哪些地址

          async:非同步,設定當前ajax請求是非同步還是同步的,不寫預設是非同步(true),如果設定為false,則代表當前請求是同步的

          使用者名稱和密碼:一般不用,如果請求的url地址所在的伺服器設定了訪問許可權,則需要提供可通行的使用者名稱和密碼才可以(一般伺服器都可以允許匿名訪問)
          
  •  ajax狀態碼和網路狀態碼詳解

 

        1.let xhr=new XMLHttpRequest()
            //不相容IE6及更低版本的瀏覽器(ie6:ActiveXObject)
        2.xhr.open([method],[url],[async],[user name],[user password]) 
            //開啟請求地址(可以理解成一些基礎配置,但並沒有傳送請求)
        3.xhr.onreadystatechange=function(){
            //監聽AJAX狀態改變,獲取響應資訊(獲取響應頭資訊,獲取響應主體資訊)
            if(xhr.readyState===4&&xhr.status===200){
                let result=xhr.responseText; //獲取響應主體中的內容
            }
        }
        
        4.xhr.send(null)
            //傳送ajax請求(括號中傳遞的內容就是請求主體的內容)




        ajax狀態碼:描述當前ajax操作的狀態的
        
        xhr.readyState

        0:UNSENT 未傳送,只要建立了一個ajax物件,預設值就是0
        1:OPEND 執行了xhr.open這個操作
        2:HEADERS_RECEIVED 當前ajax的請求已經發送,並且已經接收到伺服器端換回的響應頭資訊了
        3:LOADING 響應主體內容正在返回的路上
        4:DONE響應主體內容已經返回到客戶端




        HTTP網路狀態碼:記錄了當前伺服器返回資訊的狀態

        xhr.status

        200:成功,一個完整的HTTP事務完成(以2開頭的一般都是成功)

        以3開頭的一般也是成功,只不過伺服器做了很多別的處理
        301:永久轉移(永久重定向) 一般用於域名遷移
        302:臨時轉移(臨時重定向,新的http版本307是重定向) 一般用於伺服器的負載均衡,當前伺服器處理不了,把當前請求臨時交給其他伺服器處理,一般圖片請求經常出現302
        304:從瀏覽器快取中獲取資料  把一些不經常更新的檔案或者內容快取到瀏覽器中,下一次從快取中獲取,減輕伺服器壓力

        以4開頭的,一般都是失敗,而且是客戶端的問題
        400:請求引數錯誤
        401:無許可權訪問
        404:訪問地址不存在

        以5開頭的,一般都是失敗,而且伺服器問題偏大
        500:未知的伺服器錯誤
        503:伺服器超負載

關於網路狀態碼 我的另一篇講的更詳細請求介面返回狀態碼  

  •  AJAX中的其他常用屬性和方法詳解

 

        ajax中其他常用的屬性和方法

        面試題:ajax中總共支援幾個方法?

        let xhr = new XMLHttpRequest()
        console.dir(xhr)
        [屬性]:
            。 readyState:儲存的是當前ajax的狀態碼
            。 reasponse/responseText/responseXML:都是用來接收伺服器返回的響應主體中的內容
                只是根據伺服器返回的格式不一樣,使用不同的屬性拉接收
            。 responseText是最常用的,接收到的結果是字串格式的(一般伺服器返回的資料都是JSON格式字串)
            。 responseXML偶爾會用到,如果伺服器返回的xml文件資料,就需要用這個屬性去接收
            。 status:記錄了伺服器返回的http狀態碼
            。 statusText:對返回狀態碼的描述
            。 timeout:設定當前ajax請求的超時時間,假設設定的是3000ms,從ajax請求傳送開始,3秒後響應主體沒有返回,瀏覽器會把當前
                ajax請求任務強制斷開
        
        [方法]:
            。abort():強制中斷ajax請求
            。getAllResponseHeaders():獲取全部的響應頭資訊(獲取的結果是字串文字)
            。getResponseHeader(key):獲取指定屬性名的響應頭資訊:例如:xhr.getResponseHeader("date")獲取響應頭中儲存的伺服器時間
            。open():開啟一個url地址
            。overrideMimeType():重寫資料的MIME型別
            。send():傳送ajax請求(括號中書寫的內容是客戶端基於請求主體把資訊傳遞給伺服器)
            。setRequestHeader(key,value):設定請求頭資訊(可以是設定的自定義請求頭資訊)
     
     
        [事件]:
            。onabort:當ajax被中斷請求是觸發這個事件
            。onreadystatechange:ajax狀態發生改變觸發這個事件
            。ontimeout:當ajax請求超時,會觸發這個事件
  •  js中常用的內容編碼和加密解密方法

        js中常用的編碼編碼解碼方法

        正常的編碼解碼(非加密)
        1.escape/unescape:主要是把中文漢字進行編碼和解碼的(一般只有js語言支援:也經常應用於前端頁面通訊的時候的漢字編碼)

        2.encodeURI/decodeURI 基本上所有的程式語言都支援

        3.encodeURIComponent /decodeURIComponent

        需求:我們url問號傳遞引數的時候,引數值還是一個url或者包涵很多特殊字元,此時為了不影響主要的url
        需要把傳遞的引數值進行編碼,使用encodeURI不能編碼一些特殊字元,所以只能使用encodeURLComponent處理
  • ajax中的同步和非同步程式設計

 ajax任務:傳送請求接收到響應主體內容(完成 一個完整的http事務)

    let xhr=new XMLHttpRequest();
    xhr.open('get','temp.json',false)
    xhr.onreadystatechange=()=>{
        console.log(xhr.readyState)
    }
    xhr.send()
    //只輸出一次 結果是4



    let xhr=new XMLHttpRequest();
    xhr.open('get','temp.json')  //非同步程式設計這是
    xhr.onreadystatechange=()=>{
        console.log(xhr.readyState)
    }
    xhr.send()
    //2 3 4
  •  jq中的ajax詳解

    $.ajax({
        url:'',//設定請求api地址
        method:'get',//請求方式get/post。。。在老版本中用的是type
        dataType:'json',// datatype只是我們預設獲取結果的型別(期望的型別),不會影響伺服器的返回,伺服器一般給我們返回的都是json格式字串,
                        //如果我們預設的是json 那麼類庫中將把伺服器返回的字串轉換為json物件,如果預設的是text,我們把伺服器獲取的結果直接拿過來操作結果,我們預設的還可以是xml等
        cache:false,//設定是否清楚快取,只對GET請求起作用,預設是true不清楚快取,手動設定為false,jq會在請求的url末尾會追加一個隨機數來清楚快取
        data:null,//data可以把一些資訊傳遞給伺服器,get系列請求會把data中的內容拼接到url的末尾通過問號傳參的方式傳遞給伺服器
                    //post系列請求會把內容放在請求主體中傳遞給伺服器;data的值可以設定成兩種格式:字串和物件,如果是字串,設定的值時什麼傳遞給伺服器的就是什麼
                    //如果設定的是物件,jq會把物件變為xxx=xxx這樣的祖父穿傳遞給伺服器
        async:true,//設定同步或者非同步,預設是true代表非同步
        success:function(res){
            //當ajax請求成功(readyState===4&&status是以2或者3開頭的)
            //請求成功後jq會把傳遞的回撥函式執行,並且把獲取的結果當做實參傳遞給回撥函式
        },
        error:function(){
            //請求失敗的回撥函式
        },
        complate:function(){
            //不管是成功還是失敗都會執行   代表請求完成
        }                        
    })
  •  封裝自己的ajax庫

<script>
    ~function(){
        class ajaxClass{
            //執行ajax
            init(){
                let xhr =new XMLHttpRequest()
                xhr.onreadystatechange=()=>{
                    if(!/^[23]\d{2}$/.test(xhr.status)) return
                    if(xhr.readyState===4){
                        let result =xhr.responseText
                        switch(this.dataType.toUpperCase()){
                            case 'TEXT':
                            break
                            case 'HTML':
                            break
                            case 'JSON':
                            result=JSON.parse(result)
                            break
                            case 'XML':
                            result =xhr.responseXML
                        }
                        this.success(result)
                    }
                }
                if(this.data!==null){
                    this.farmatData()
                    if(this.isGET){
                        this.url+=this.querySymbol()+this.data
                        this.data=null
                    }
                }
                this.isGET?this.cache():null
                xhr.open(this.method,this.url,this.async)
                xhr.send()
                
            }

            farmatData(){
                if(({}).toString.call(this.call)==="[object Object]"){
                    let obj=this.data
                    str=''
                    for(let key in obj){
                        if(obj.hasOwnProperty(key)){
                            str+=`${key}=${obj[key]}&`;
                        }
                    }
                    str=str.replace(/&$/g,'')
                    this.data=str
                }
            }
            cacheFn(){
                if(!this.cache){
                    !this.cache?this.url+=`${this.querySymbol()}_=${Math.random()}`:null
                }
            }
            querySymbol(){
                 return this.url.indexOf("?")>-1?'&':'?'
            }
        }
        //引數初始化
        window.ajax=function({url=null,method='GET',type='GET',data=null,dataType='JSON',cache=true,async=true,success=null}={}){
            let example= new ajaxClass()
            example.url=url
            example.method=type===null?method:type
            example.data=data
            example.dataType=dataType
            example.cache=cache
            example.async=async
            example.success=typeof success ==='function'?success: new Function()
            example.isGET=/^(get|delete|head)$/i.test(example.method)
            example.init()

        }
    }()
</script>