JavaScript全解析——Ajax(下)
Ajax(下)
●http 傳輸協(xié)議
○http(s) 協(xié)議規(guī)定了, 只能由前端主動發(fā)起
○并且在傳輸?shù)倪^程中, 只能傳遞 字符串
●http 協(xié)議過程
1.建立連接
瀏覽器和服務器進行連接建立
基于 TCP/IP 協(xié)議的三次握手
2.發(fā)送請求
要求前端必須以 請求報文 的形式發(fā)送
報文由瀏覽器組裝, 我們只需要提供對應的信息即可
報文包含的內容
3.接收響應
要求后端必須以響應報文的形式返回
報文由服務器組裝
響應報文包含的內容
響應報文行
響應狀態(tài)碼, 簡單信息描述響應狀態(tài)碼, 傳輸協(xié)議
響應報文頭(對本次響應的一些說明信息)
server: 哪一個服務器給你返回的信息
date: 時間, 服務器時間
content-length: 響應體長度
content-type: 響應數(shù)據(jù)類型
響應報文體(后端返回給前端的一些信息)
4.斷開連接
瀏覽器和服務器斷開連接
基于 TCP/IP 協(xié)議的四次揮手
●響應狀態(tài)碼
○100199 表示連接繼續(xù)299 表示各種成功
○200
○300399 表示重定向499 表示各種客戶端錯誤
○400
○500~599 表示各種服務端錯誤
●回調函數(shù)
○把函數(shù) A 以實參的形式傳遞到 函數(shù) B 內
○在函數(shù) B 內以形參的方式調用到 函數(shù) A
○此時我們可以把函數(shù) A 叫做函數(shù) B 的 回調函數(shù)
○我們在封裝異步代碼的時候會用到回調函數(shù)
●使用回調函數(shù)封裝一個異步代碼
●上述代碼已經(jīng)完成了一個異步的封裝
●不過在工作中我們更多的是封裝網(wǎng)絡請求這種異步代碼
●但是我們這里通過一個 '買水耗時' 來模擬一個網(wǎng)絡請求的延遲, 我們約定如果時間超過 3500 毫秒, 那么就算是失敗, 否則就是成功
●此時我們已經(jīng)封裝完畢了, 只不過這種封裝方式會帶來另一個問題, 就是回調地獄
●回調地獄: 當你使用回調函數(shù)過多的時候, 會出現(xiàn)的一種代碼書寫結構
●需求:
○再買水成功后, 讓班長幫忙退掉
○在推掉以后, 再次讓班長幫忙買水 (此時必須要在前一瓶水購買完成之后再去購買)
○在第二次買水成功以后, 再次讓班長去買水
●這段代碼運行沒有任何問題, 但是閱讀起來極其不利于理解
○原因:
■按照回調函數(shù)的語法進行封裝, 只能通過傳遞一個函數(shù)作為參數(shù)來調用
■當你使用回調函數(shù)過多的時候, 會出現(xiàn)回調地獄的代碼結構
○解決:
■不按照回調函數(shù)的語法封裝
■ES6 推出了一種新的封裝異步代碼的方式, 叫做 Promise (承諾, 期約)
Promise
是一種異步代碼的封裝方案
因為換了一種封裝方案, 不需要安裝回調函數(shù)的方式去調用, 需要按照 promise 的形式去調用
注意 promise 不是解決 異步問題的, 而是解決回調地獄問題的
●認識 Promise
○promise 的三種狀態(tài)
■持續(xù): pending
■成功: fulfilled
■失敗: rejected
○promise 的兩種轉換
■從持續(xù)轉為成功
■從持續(xù)轉為失敗
○promise 的基礎語法
■ES6 內置構造函數(shù)
○promise 的語法
■const p = new Promise(function () {})
○promise 對象可以觸發(fā)的兩個方法
■p.then(函數(shù)); 成功時執(zhí)行
■p.catch(函數(shù)); 失敗時執(zhí)行
●promise 封裝一個異步函數(shù)
● 封裝 promise 為函數(shù)
●promise 的鏈式調用
●promise 的調用方式補充
○如果你在第一個 then 里面返回(return) 一個新的 promise 對象的時候
○可以在第一個 then 后面, 繼續(xù)第二個 then
●promise 的其他方法
●Promise 實例的 finally 方法
○不管promise是成功還是失敗, 只要 promise 執(zhí)行結束, 我都會執(zhí)行
● Promise 本身還有一些方法
○all:
■作用: 可以同時觸發(fā)多個 promise 行為
●只有所有的 promise 都成功的時候, all 才算成功
●只要任何一個 promise 失敗的時候, all 就算失敗了
■語法: Promise.all([多個 promise])
○race:
■作用: 可以同時觸發(fā)多個 promise 行為
●按照速度計算, 當?shù)谝粋€結束的時候就結束了, 成功或失敗取決于第一個執(zhí)行結束的 promise
■語法: Promise.race([多個 promise])
○allSettled
■作用: 可以同時觸發(fā)多個 Promise 行為
●不管多個成功還是失敗都會觸發(fā)
●會在結果內以數(shù)組的形式給你返回 每一個 promise 行為的成功還是失敗
■語法: Promise.allSettled([多個 promise])
○resolve
■作用: 強制返回一個成功狀態(tài)的 promise 對象
○reject
■作用: 強制返回一個失敗狀態(tài)的 promise 對象
●async / await
上述我們已經(jīng)把 promise 的基礎使用掌握了, 但是個人認為, promise 的鏈式調用仍然會有點小問題
就是在使用的時候, 過多的鏈式調用, 對于閱讀體驗來說, 仍然是有一點小問題, 不利于閱讀
所以我們可以 使用 ES6+ 新推出的 async與await, 使用我的異步代碼書寫的更像是同步代碼一樣
●注意: 需要配合的必須是 Promise
●async 關鍵字的用法:
○直接書寫在函數(shù)的前面即可, 表示該函數(shù)是一個異步函數(shù)
○意義: 表示在該函數(shù)內部可以使用 await 關鍵字
●await 關鍵字的用法:
○必須書寫在一個有 async 關鍵字的函數(shù)內
○await 后面等待的內容必須是一個 promise 對象
○本該使用 then 接受的結果, 可以直接定義變量接受了
●常規(guī)的 promise 調用方式
●利用 async 和 await 關鍵字來使用
●async 和 await 語法的缺點
○await 只能捕獲到 Promise 成功的狀態(tài)
○如果失敗, 會報錯并且終止程序的繼續(xù)執(zhí)行
● 解決方法1: 使用 try...catch...
○語法: try { 執(zhí)行代碼 } catch (err) { 執(zhí)行的代碼 }
○首先執(zhí)行 try 內部的代碼, 如果不報錯, catch 的代碼不執(zhí)行了
○如果報錯, 不會爆出錯誤, 不會終止程序, 而是執(zhí)行 catch 的代碼, 報錯信息在 catch 函數(shù)的形參內
●解決方法2: 改變封裝的思路
○原因: 因為 promise 對象有成功和失敗的狀態(tài), 所以會在失敗狀態(tài)是報錯
○解決: 封裝一個 百分比成功的 promise 對象, 讓成功和失敗的時候都按照 resolve 的形式來執(zhí)行
○只不過傳遞出去的參數(shù), 記錄一個表示成功或者失敗的信息
●封裝 ajax
1.ajax 封裝解析
a.封裝方案
i.選擇回調函數(shù)
1.將來使用的時候需要按照回調函數(shù)的語法使用
2.但是容易出現(xiàn)回調地獄
ii.選擇 promise 的形式
1.按照 Promise 的形式來使用
2.后續(xù)可以利用 async/await 語法進一步簡化代碼
b.決定參數(shù)
i. 請求地址(url): 必填
ii.請求方式(method): 選填, 默認 GET
iii.是否異步(async): 選填, 默認 true 異步
iv.攜帶的參數(shù)(data): 選填, 默認 '' 空字符
c.決定返回值
i.需要
ii.返回一個 promise 對象
1.因為需要依賴返回值來決定使用 then 還是 catch
d.參數(shù)書寫順序
i.因為有多個參數(shù), 并且有些參數(shù)可以有默認值
ii.所以我們只能通過傳遞一個對象的方式去處理
2.ajax 封裝參數(shù)驗證
3.ajax 封裝默認值
4.ajax 封裝發(fā)送請求
5.ajax 封裝請求頭信息
6.ajax 封裝解析參數(shù)
7.ajax 封裝基準地址
8.完整版 ajax 封裝代碼