Ajax如何理解

什么是ajax

●認識前后端交互
????○就是 前端 與 后端的 一種通訊方式
????○主要使用的技術棧就是 ajax (async javascript and xml)
●ajax 特點
????○使用 ajax 技術網頁應用能夠快速的將新內容呈現在用戶界面
????○并且不需要刷新整個頁面, 也就是能夠讓頁面有 "無刷更新" 的效果
●注意點:
????○前后端交互只能交互 字符串
????○并且有自己的固定步驟
創建ajax 基本步驟的是什么
1.創建 ajax 對象

const xhr = new XMLHttpRequest()

2.配置 ajax 對象

// xhr.open('請求的方式', '請求的地址', 是否異步)xhr.open('GET', 'http://localhost:8888/test/first', true)

3.發送請求

xhr.send()

4.接收響應???????

xhr.onload = function () {    console.log('請求回來了~~~~~~~~')    console.log(xhr.responseText)}

ajax 狀態碼有哪些

●簡單來說其實就是用一個數字表明了當前 ajax 運行到哪一步了
●語法: xhr.readyState
????○0: 創建 ajax 成功
????○1: 當前 ajax 配置成功
????○2: 當前 ajax 發送成功(響應已經回到瀏覽器了)
????○3: 表示瀏覽器當前正在解析本次響應, 但可能還沒完成
????○4: 表示瀏覽器已經完成解析本次響應, 可以正常使用 responseText 了
●0 和 1, 比較好打印, 2/3/4 這幾個我們可以借助一個 事件去打印
????○readyStatechange 事件
????○通過事件名其實就可以看出, 當 readyState 發生改變時就會執行???????

const xhr = new XMLHttpRequest()console.log(xhr.readyState) // 0
xhr.open('GET', 'http://localhost:8888/test/first', true)console.log(xhr.readyState) // 1
xhr.onreadystatechange = function () {    if (xhr.readyState === 2) console.log(xhr.responseText)     if (xhr.readyState === 3) console.log(xhr.responseText)     if (xhr.readyState === 4) console.log(xhr.responseText) }
xhr.send()

ajax 常見請求方式有哪些

● GET
????○表示向服務器獲取資源
●POST
????○表示向服務器提交信息,通常用于產生新的數據,比如注冊
●PUT
????○表示希望修改服務器的數據, 通常用于修改某數據
●DELETE
????○表示希望刪除服務器的數據
●OPTIONS
????○發生在跨域的預檢請求中,表示客戶端向服務器申請跨域提交
ajax 中 get 和 post 請求攜帶參數的方式
●GET: 直接拼接在請求路徑后, 以 ? 間隔, 使用 key=value 的形式書寫, 當有多個參數的時候用 & 連接???????

const xhr = new XMLHttpRequest()xhr.open('GET', 'http://localhost:8888/test/third?name=QF666&age=18')xhr.send()xhr.onload = function () {    let res = JSON.parse(xhr.responseText)    console.log(res)}

●POST
????○在請求體內攜帶參數(其實就是 send 小括號內部)
????○并且需要設置請求頭內部的 content-type
????????■如果參數為 查詢字符串, 需要添加:
????????????●'xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')'
????????■如果參數為 JSON 字符串, 需要添加:
????????????●'xhr.setRequestHeader('content-type', 'application/json')'???????

const xhr = new XMLHttpRequest()xhr.open('POST', 'http://localhost:8888/test/fourth')xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')xhr.send('name=QF666&age=18')xhr.onload = function () {    let res = JSON.parse(xhr.responseText)    console.log(res)}

ajax 中 get 和 post 的區別有哪些

????1.攜帶參數的位置
????????a.GET: 直接在地址后面書寫
????????b.POST: 在請求體內書寫
????2.攜帶參數的大小
????????a.GET: 2kb(左右)
????????b.POST: 原則上不限制大小, 但是服務器可以做出限制
????3.攜帶參數的格式
????????a.GET: 只能攜帶查詢字符串格式
????????b.POST: 原則上不限制格式, 但是需要在請求報文的 content-type 做出配置
????4.安全性(相對)
????????a.GET: 明文發送, 相對不安全
????????b.POST: 暗文發送, 相對安全

●http 傳輸協議

????○http(s) 協議規定了, 只能由前端主動發起
????○并且在傳輸的過程中, 只能傳遞 字符串

●http 協議過程

????1.建立連接

????????瀏覽器和服務器進行連接建立
????????基于 TCP/IP 協議的三次握手

????2.發送請求

????????要求前端必須以 請求報文 的形式發送

????????報文由瀏覽器組裝, 我們只需要提供對應的信息即可

????????報文包含的內容

???????????? 請求報文行

?????????????請求方式, 請求地址, 傳輸協議

?????????????請求報文頭(對本次請求的一些說明信息)

?????????????userAgent: 請求方終端信息

?????????????accept: 期望后端返回的數據類型

?????????????content-type: 請求攜帶的 "材料" 的數據格式

?????????????cookie: 只要 cookie 空間內有內容, 會自動攜帶

????????請求報文空行

????????請求報文體(不是所有請求都有)

????3.? 接收響應

? ? ? ??要求后端必須以響應報文的形式返回

? ? ? ? 報文由服務器組裝

????????響應報文包含的內容

? ? ? ? ? ? ? ? 響應報文行

? ? ? ? ? ? ? ? 響應狀態碼, 簡單信息描述響應狀態碼, 傳輸協議

? ? ? ? ?響應報文頭(對本次響應的一些說明信息)

????????????????server: 哪一個服務器給你返回的信息

? ? ? ? ? ? ? ? date: 時間, 服務器時間

? ? ? ? ? ? ? ? content-length: 響應體長度

? ? ? ? ? ? ? ? content-type: 響應數據類型

????????????????響應報文體(后端返回給前端的一些信息)

????4.? 斷開連接

????????? 瀏覽器和服務器斷開連接

? ? ? ? ?基于 TCP/IP 協議的四次揮手

●?響應狀態碼

????○?100~199 表示連接繼續

????○?200~299 表示各種成功

????○?300~399 表示重定向

????○?400~499 表示各種客戶端錯誤

????○?500~599 表示各種服務端錯誤

●?回調函數

????○?把函數 A 以實參的形式傳遞到 函數 B 內

????○?在函數 B 內以形參的方式調用到 函數 A

????○?此時我們可以把函數 A 叫做函數 B 的 回調函數

????○?我們在封裝異步代碼的時候會用到回調函數???????

function fnA () {console.log('我是 fnA 函數內部的代碼')}
function fnB(callback) {callback()}
fnB(fnA)

●?使用回調函數封裝一個異步代碼???????

function fn(jinnang = () => {}) {    console.log("班長去買水了");    const timer = Math.ceil(Math.random() * 3000);    setTimeout(() => {        console.log("班長買完水了");        console.log("耗時", timer);        console.log("按照錦囊內的內容行事");        jinnang();    }, timer);}/** * fn 函數一旦調用, 班長出發開始去買水 *      在班長出發的時候, 給他一個錦囊 */fn(() => {    console.log("去買一瓶牛奶");});fn();

●?上述代碼已經完成了一個異步的封裝

●?不過在工作中我們更多的是封裝網絡請求這種異步代碼

●?但是我們這里通過一個 '買水耗時' 來模擬一個網絡請求的延遲, 我們約定如果時間超過 3500 毫秒, 那么就算是失敗, 否則就是成功???????

function fn(jinnang = () => {}) {    console.log("班長去買水了");    const timer = Math.ceil(Math.random() * 3000) + 2000;    setTimeout(() => {        if (timer > 3500) {            console.log("請求失敗", timer);        } else {            console.log("請求成功", timer);        }    }, timer);}/** * fn 函數一旦調用, 班長出發開始去買水 *      在班長出發的時候, 給他一個錦囊 */fn(() => {    console.log("去買一瓶牛奶");});fn();

●?此時我們已經封裝完畢了, 只不過這種封裝方式會帶來另一個問題, 就是回調地獄

●?回調地獄: 當你使用回調函數過多的時候, 會出現的一種代碼書寫結構

●?需求:

????○?再買水成功后, 讓班長幫忙退掉

????○?在推掉以后, 再次讓班長幫忙買水 (此時必須要在前一瓶水購買完成之后再去購買)

????○?在第二次買水成功以后, 再次讓班長去買水???????

fn(    () => {        console.log("班長第一次買水成功, 幫我退掉");        fn(            () => {                console.log("班長第二次買水成功");                fn(                    () => {                        console.log("班長第三次買水成功");                    },                    () => {                        console.log("班長第三次買水失敗");                    }                );            },            () => {                console.log("班長第二次買水失敗");            }        );    },    () => {        console.log("班長第一次買水失敗");    });

●這段代碼運行沒有任何問題, 但是閱讀起來極其不利于理解
????○原因:
????????■按照回調函數的語法進行封裝, 只能通過傳遞一個函數作為參數來調用
????????■當你使用回調函數過多的時候, 會出現回調地獄的代碼結構
????○解決:
????????■不按照回調函數的語法封裝
????????■ES6 推出了一種新的封裝異步代碼的方式, 叫做 Promise (承諾, 期約)

Promise

是一種異步代碼的封裝方案
因為換了一種封裝方案, 不需要安裝回調函數的方式去調用, 需要按照 promise 的形式去調用
注意 promise 不是解決 異步問題的, 而是解決回調地獄問題的

●認識 Promise

????○promise 的三種狀態
????????■持續: pending
????????■成功: fulfilled
????????■失敗: rejected

????○promise 的兩種轉換
????????■從持續轉為成功
????????■從持續轉為失敗

????○promise 的基礎語法
????????■ES6 內置構造函數

????○promise 的語法
????????■const p = new Promise(function () {})

????○promise 對象可以觸發的兩個方法
????????■p.then(函數); 成功時執行
????????■p.catch(函數); 失敗時執行
●promise 封裝一個異步函數

???????

const p = new Promise(function (resolve, reject) {    // resolve: 是一個形參, 名字自定義, 值是一個函數, 當你調用的時候, 會把當前 promise 的狀態轉換為 成功    // reject: 是一個形參, 名字自定義, 值是一個函數, 當你調用的時候, 會把當前 promise 的狀態轉換為 失敗    // resolve 和 reject 調用時可以傳遞一個參數, 這個參數會被傳遞給對應的 then catch    const timer = Math.ceil(Math.random() * 3000) + 2000;    setTimeout(() => {        if (timer > 3500) {            console.log("買水失敗, 耗時 ", timer);            reject("獎勵一個bug");        } else {            console.log("買水成功, 耗時: ", timer);            resolve("送你十個bug");        }    }, timer);});
p.then(function (address) {    console.log("班長買水成功咯~~~", address);});p.catch(function (address) {    console.log("班長買水失敗咯~~~", address);});

● 封裝 promise 為函數???????

function fn() {    const p = new Promise(function (resolve, reject) {        const timer = Math.ceil(Math.random() * 3000) + 2000;        setTimeout(() => {            if (timer > 3500) {                reject("班長買水失敗");            } else {                resolve("班長買水成功");            }        }, timer);    });    return p;}// 將來在使用的時候 res 得到的是 promise 的實例對象 p
const res = fn();res.then(function (type) {    // 這個函數執行代碼 promise 狀態為成功狀態!!!    console.log("因為", type, "謝謝班長, 我準備了20個bug, 回饋給你");});res.catch(function (type) {    // 這個函數執行代碼    console.log("因為", type, "謝謝班長, 我準備了800個bug, 開心死你");});

●promise 的鏈式調用

???????

fn()    .then(function (type) {        // 這個函數執行代碼 promise 狀態為成功狀態!!!        console.log("因為", type, "謝謝班長, 我準備了20個bug, 回饋給你");    })    .catch(function (type) {        // 這個函數執行代碼        console.log("因為", type, "謝謝班長, 我準備了800個bug, 開心死你");    });

●promise 的調用方式補充

????○如果你在第一個 then 里面返回(return) 一個新的 promise 對象的時候
????○可以在第一個 then 后面, 繼續第二個 then???????

fn()    .then(function (type) {        console.log(            "第一次: 因為",            type,            "謝謝班長, 我準備了20個bug, 回饋給你"        );        return fn();    })    .then(function (type) {        console.log(            "第二次: 因為",            type,            "謝謝班長, 我準備了20個bug, 回饋給你"        );        return fn();    })    .then(function (type) {        console.log(            "第三次: 因為",            type,            "謝謝班長, 我準備了20個bug, 回饋給你"        );        return fn();    })    .catch(function (type) {        console.log("因為", type, "謝謝班長, 我準備了800個bug, 開心死你");    });

●promise 的其他方法

●Promise 實例的 finally 方法

????○不管promise是成功還是失敗, 只要 promise 執行結束, 我都會執行???????

fn()    .then(function (res) {        console.log("成功");    })    .catch(function (res) {        console.log("失敗");    })    .finally(function () {        console.log(            "不管promise是成功還是失敗, 只要 promise 執行結束, 我都會執行"        );    });

● Promise 本身還有一些方法

????○all:
????????■作用: 可以同時觸發多個 promise 行為
????????????●只有所有的 promise 都成功的時候, all 才算成功
????????????●只要任何一個 promise 失敗的時候, all 就算失敗了
????????■語法: Promise.all([多個 promise])

○race:
????????■作用: 可以同時觸發多個 promise 行為
????????????●按照速度計算, 當第一個結束的時候就結束了, 成功或失敗取決于第一個執行結束的 promise
????????■語法: Promise.race([多個 promise])

○allSettled
????????■作用: 可以同時觸發多個 Promise 行為
????????????●不管多個成功還是失敗都會觸發
????????????●會在結果內以數組的形式給你返回 每一個 promise 行為的成功還是失敗
????????■語法: Promise.allSettled([多個 promise])

○resolve
????????■作用: 強制返回一個成功狀態的 promise 對象

○reject
????????■作用: 強制返回一個失敗狀態的 promise 對象

???????

// 1. allPromise.all([fn(), fn(), fn()])    .then(function () {        console.log("所有的 參數 都返回 成功狀態");    })    .catch(function () {        console.log("這些參數中, 有一個 為 失敗狀態");    });// 2. racePromise.race([fn(), fn(), fn()])    .then(function () {        console.log("速度最快的那個執行完畢, 并且是成功狀態時 執行");    })    .catch(function () {        console.log("速度最快的那個執行完畢, 并且是失敗狀態時 執行");    });// 3. allSettledPromise.allSettled([fn(), fn(), fn()])    .then(function (res) {        console.log(res);    })    .catch(function (res) {        console.log(res);    });// 4. resolvePromise.resolve()    .then(function (res) {        console.log("成功");    })    .catch(function (res) {        console.log("失敗");    });// 5. rejectPromise.reject()    .then(function (res) {        console.log("成功");    })    .catch(function (res) {        console.log("失敗");    });

●async / await

上述我們已經把 promise 的基礎使用掌握了, 但是個人認為, promise 的鏈式調用仍然會有點小問題
就是在使用的時候, 過多的鏈式調用, 對于閱讀體驗來說, 仍然是有一點小問題, 不利于閱讀
所以我們可以 使用 ES6+ 新推出的 async與await, 使用我的異步代碼書寫的更像是同步代碼一樣

●注意: 需要配合的必須是 Promise
●async 關鍵字的用法:
????○直接書寫在函數的前面即可, 表示該函數是一個異步函數
????○意義: 表示在該函數內部可以使用 await 關鍵字
●await 關鍵字的用法:
????○必須書寫在一個有 async 關鍵字的函數內
????○await 后面等待的內容必須是一個 promise 對象
????○本該使用 then 接受的結果, 可以直接定義變量接受了
●常規的 promise 調用方式

???????

fn()    .then(function (res) {        console.log(res);    })    .catch(function (res) {        console.log(res);    });

●利用 async 和 await 關鍵字來使用

???????

async function newFn() {    /**     * await 是等待的意思     *     *  在當前 fn 函數內, await 必須要等到后面的 Promise 結束以后, 才會繼續執行后續代碼     */    const r1 = await fn();    console.log("第一次: ", r1);    const r2 = await fn();    console.log("第二次: ", r1);    const r3 = await fn();    console.log("第三次: ", r1);}
newFn();

●async 和 await 語法的缺點
????○await 只能捕獲到 Promise 成功的狀態
????○如果失敗, 會報錯并且終止程序的繼續執行???????

async function newFu() {    const r1 = await fn();    console.log("失敗后, 提示用戶網絡錯誤"); // 如果失敗的話這行代碼并不會執行}newFu();

● 解決方法1: 使用 try...catch...
????○語法: try { 執行代碼 } catch (err) { 執行的代碼 }
????○首先執行 try 內部的代碼, 如果不報錯, catch 的代碼不執行了
????○如果報錯, 不會爆出錯誤, 不會終止程序, 而是執行 catch 的代碼, 報錯信息在 catch 函數的形參內

???????

async function newFu() {    try {        const r1 = await fn();        console.log(r1);    } catch (error) {        console.log("網絡錯誤, 請檢查網絡并重新請求");    }}newFu();

●解決方法2: 改變封裝的思路
????○原因: 因為 promise 對象有成功和失敗的狀態, 所以會在失敗狀態是報錯
????○解決: 封裝一個 百分比成功的 promise 對象, 讓成功和失敗的時候都按照 resolve 的形式來執行
????○只不過傳遞出去的參數, 記錄一個表示成功或者失敗的信息

???????

function fn() {    const p = new Promise(function (resolve, reject) {        const timer = Math.ceil(Math.random() * 3000) + 2000;        setTimeout(() => {            if (timer > 3500) {                resolve({ code: 0, msg: "班長買水失敗" });            } else {                resolve({ code: 1, msg: "班長買水成功" });            }        }, timer);    });    return p;}
async function newFn() {    const r1 = await fn();    if (r1.code === 0) {        console.log("第一次請求失敗, 請檢查您的網絡信息");    } else {        console.log("第一次請求成功", r1.msg);    }
    const r2 = await fn();    if (r2.code == 0) {        console.log("第二次請求失敗, 請檢查您的網絡信息");    } else {        console.log("第二次請求成功", r2.msg);    }}newFn();

●封裝 ajax

1.ajax 封裝解析

????a.封裝方案

????????i.選擇回調函數

????????????1.將來使用的時候需要按照回調函數的語法使用
????????????2.但是容易出現回調地獄

????????ii.選擇 promise 的形式

????????????1.按照 Promise 的形式來使用
????????????2.后續可以利用 async/await 語法進一步簡化代碼

????b.決定參數

????????i. 請求地址(url): 必填
????????ii.請求方式(method): 選填, 默認 GET
????????iii.是否異步(async): 選填, 默認 true 異步
????????iv.攜帶的參數(data): 選填, 默認 '' 空字符

????c.決定返回值

????????i.需要
????????ii.返回一個 promise 對象
????????????1.因為需要依賴返回值來決定使用 then 還是 catch
????d.參數書寫順序
????????i.因為有多個參數, 并且有些參數可以有默認值
????????ii.所以我們只能通過傳遞一個對象的方式去處理

function ajax(options) {}

2.ajax 封裝參數驗證????????????????

function ajax(options = {}) {    // 1.1 驗證參數---url 必傳    if (options.url == undefined) throw new Error("url 為必填項, 請填寫后再試");
    // 1.2 驗證參數---method 可以不傳, 可以為 GET, 可以是 POST, 但不能是其他的    if (        !(options.method === undefined || /^(GET|POST)$/i.test(options.method))    ) {        throw new Error("mehtod 目前僅支持 GET 或 POST");    }    // 1.3 驗證參數---async 可以不傳, 可以為 true, 可以是 false, 但不能是其他的    if (!(options.async === undefined || typeof options.async === "boolean")) {        throw new Error("async 目前僅支持 布爾值(Boolean)");    }    // 1.4 驗證參數---data 可以不傳, 可以為一個字符串, 可以是一個對象    if (        !(            options.data === undefined ||            typeof options.data === "string" ||            options.data.constructor === Object        )    ) {        throw new Error("data 目前僅支持 字符串(String) 或 對象(Object)");    }
    // console.log('這里執行說明參數的 url 已經傳遞了')}
ajax({    url: "qwer",    // method: 'POST',    // async: false,    data: "name=QF666&age=18",});

3.ajax 封裝默認值???????

function objToStr(obj) {    let str = "";
    for (let k in obj) {        str += `${k}=${obj[k]}&`;    }
    return str.slice(0, str.length - 1);}
function ajax(options = {}) {    // 1 驗證參數---代碼省略
    // 2.1 處理默認值    const _options = {        url: options.url,        // 代碼執行到這里, method 要么是 undefined 要么是 GET或者POST        method: options.method || "GET",        // 代碼執行到這里, async 要么是 undefined 要么是 true 或者 false        // ?? 空值運算符, 只有在 左側為 undefined 或者 null 時才會執行右邊的        async: options.async ?? true,        // 代碼執行到這里, data 要么是 undefined 要么是 '' 或者 {}        data: options.data || "",    };    // 2.2 如果當前 data 是對象, 需要轉換為 查詢字符串    if (typeof _options.data !== "string") {        _options.data = objToStr(_options.data);    }    // 2.3 如果當前 data 有值, 且當前是 GET 方式, 那么可以提前 把 url 后拼接上 data    if (_options.data && /^(GET)$/i.test(_options.method)) {        _options.url += "?" + _options.data;    }
    console.log("原始參數: ", options);    console.log("默認參數: ", _options);
    // console.log('這里執行說明參數的 url 已經傳遞了')}

4.ajax 封裝發送請求???????

function ajax(options = {}) {    // 1 驗證參數---代碼省略    // 2 處理默認參數---代碼省略        // 3. 封裝 ajax 請求    const p = new Promise((resolve, reject) => {        // 3.1 創建 ajax        const xhr = new XMLHttpRequest();
        // 3.2 配置 ajax 請求信息        xhr.open(_options.method, _options.url, _options.async);
        // 3.3 配置接收響應的事件        xhr.onload = function () {            resolve(xhr.responseText);        };
        // 3.4 發送本次請求        xhr.send();    });    return p;}
ajax({    url: "http://localhost:8888/test/third",    // method: "POST",    async: false,    data: "name=QF666&age=18",    // data: {    //     name: "QF666",    //     age: 18,    //     abc: 123,    // },}).then((res) => {    console.log(res);});

5.ajax 封裝請求頭信息???????

function ajax(options = {}) {    // 1 驗證參數---部分代碼省略    // 1.5 驗證參數---headers 可以不傳, 可以為一個對象    if (        !(            options.headers === undefined ||            options.headers.constructor === Object        )    ) {        throw new Error("herder 目前僅支持對象(Object)");    }
    // 2.1 處理默認值    const _options = {        // code...        // 代碼執行到這里, headers 要么是 undefined 要么是 {}        headers: {            "content-type": "application/x-www-form-urlencoded",            ...options.headers,        },    };
    // 3. 封裝 ajax 請求    const p = new Promise((resolve, reject) => {        // 3.1 創建 ajax        // 3.2 配置 ajax 請求信息        // 3.3 配置接收響應的事件
        // 如果當前的請求方式為 POST, 那么需要配置上對應的 請求頭        if (/^(POST)$/i.test(_options.method)) {            xhr.setRequestHeader(                "content-type",                _options.headers["content-type"]            );        }        // 如果 authorization 內有值, 需要帶上 authorization        if (_options.headers.authorization) {            xhr.setRequestHeader(                "authorization",                _options.headers.authorization            );        }        // 3.4 發送本次請求        /^(POST)$/i.test(_options.method)            ? xhr.send(_options.data)            : xhr.send();    });    return p;}
/** *  思考: 請求頭的設置 *      + 當你是 post 的時候, 需要設置 content-type 字段 *      + 有的時候還需要設置 authorization 字段 *      + 有的時候還需要設置 abcd 字段 * *  例子: *      1. 登錄 *          + POST 方式 *              => 需要 content-type *              => 不需要 authorization *      2. 獲取商品列表 *          + GET 方式 *              => 不需要 content-type *              => 不需要 authorization *      3. 獲取購物車列表 *          + GET 方式 *              => 不需要設置 content-type *              => 需要 authorization *      4. 修改密碼 *          + POST 方式 *              => 需要 content-type *              => 需要 authorization */
ajax({    url: "http://localhost:8888/test/third",    // method: "POST",    // async: false,    // data: "name=QF666&age=18",    data: {        name: "QF666",        age: 18,        abc: 123,    },    headers: { authorization: "123" },}).then((res) => {    console.log(res);});

6.ajax 封裝解析參數???????

function ajax(options = {}) {    // 1.6 驗證參數---dataType 可以不傳, 可以為 'string' 可以為 'json'    if (        !(            options.dataType === undefined ||            /^(string|json)$/i.test(options.dataType)        )    ) {        throw new Error("dataType 目前僅支持 'string' 或者 'json' ");    }
    // 2.1 處理默認值    const _options = {        // 代碼執行到這里, dataType 要么是 undefined 要么是 string 要么是 json        dataType: options.dataType || "string",    };
    // 3. 封裝 ajax 請求    const p = new Promise((resolve, reject) => {        // 3.3 配置接收響應的事件        xhr.onload = function () {            if (_options.dataType === "string") {                resolve({                    code: 1,                    info: xhr.responseText,                    msg: "成功",                });                return;            }
            try {                const res = JSON.parse(xhr.responseText);                resolve({                    code: 1,                    info: res,                    msg: "成功",                });            } catch (error) {                resolve({                    code: 0,                    info: error,                    msg: "失敗",                });            }        };    });    return p;}

7.ajax 封裝基準地址???????

function outer(url) {    let baseUrl = url;
    function ajax(options = {}) {        // 2.1 處理默認值        const _options = {            url: baseUrl + options.url,        };                // 省略部分代碼...    }    return ajax;}
const res = outer("http://localhost:8888");
res({    url: "/test/first",}).then((res) => {    console.log(res);});
res({    url: "/test/second",    dataType: "json",}).then((res) => {    console.log(res);});

8.完整版 ajax 封裝代碼???????

function objToStr(obj) {    let str = "";
    for (let k in obj) {        str += `${k}=${obj[k]}&`;    }
    return str.slice(0, str.length - 1);}
function outer(url) {    let baseUrl = url;
    function ajax(options = {}) {        // 1.1 驗證參數---url 必傳        if (options.url == undefined)            throw new Error("url 為必填項, 請填寫后再試");
        // 1.2 驗證參數---method 可以不傳, 可以為 GET, 可以是 POST, 但不能是其他的        if (            !(                options.method === undefined ||                /^(GET|POST)$/i.test(options.method)            )        ) {            throw new Error("mehtod 目前僅支持 GET 或 POST");        }        // 1.3 驗證參數---async 可以不傳, 可以為 true, 可以是 false, 但不能是其他的        if (            !(options.async === undefined || typeof options.async === "boolean")        ) {            throw new Error("async 目前僅支持 布爾值(Boolean)");        }        // 1.4 驗證參數---data 可以不傳, 可以為一個字符串, 可以是一個對象        if (            !(                options.data === undefined ||                typeof options.data === "string" ||                options.data.constructor === Object            )        ) {            throw new Error("data 目前僅支持 字符串(String) 或 對象(Object)");        }        // 1.5 驗證參數---headers 可以不傳, 可以為一個對象        if (            !(                options.headers === undefined ||                options.headers.constructor === Object            )        ) {            throw new Error("herder 目前僅支持對象(Object)");        }        // 1.6 驗證參數---dataType 可以不傳, 可以為 'string' 可以為 'json'        if (            !(                options.dataType === undefined ||                /^(string|json)$/i.test(options.dataType)            )        ) {            throw new Error("dataType 目前僅支持 'string' 或者 'json' ");        }
        // 2.1 處理默認值        const _options = {            url: baseUrl + options.url,            // 代碼執行到這里, method 要么是 undefined 要么是 GET或者POST            method: options.method || "GET",            // 代碼執行到這里, async 要么是 undefined 要么是 true 或者 false            // ?? 空值運算符, 只有在 左側為 undefined 或者 null 時才會執行右邊的            async: options.async ?? true,            // 代碼執行到這里, data 要么是 undefined 要么是 '' 或者 {}            data: options.data || "",            // 代碼執行到這里, headers 要么是 undefined 要么是 {}            headers: {                "content-type": "application/x-www-form-urlencoded",                ...options.headers,            },            // 代碼執行到這里, dataType 要么是 undefined 要么是 string 要么是 json            dataType: options.dataType || "string",        };        // 2.2 如果當前 data 是對象, 需要轉換為 查詢字符串        if (typeof _options.data !== "string") {            _options.data = objToStr(_options.data);        }        // 2.3 如果當前 data 有值, 且當前是 GET 方式, 那么可以提前 把 url 后拼接上 data        if (_options.data && /^(GET)$/i.test(_options.method)) {            _options.url += "?" + _options.data;        }
        // 3. 封裝 ajax 請求        const p = new Promise((resolve, reject) => {            // 3.1 創建 ajax            const xhr = new XMLHttpRequest();
            // 3.2 配置 ajax 請求信息            xhr.open(_options.method, _options.url, _options.async);
            // 3.3 配置接收響應的事件            xhr.onload = function () {                if (_options.dataType === "string") {                    resolve({                        code: 1,                        info: xhr.responseText,                        msg: "成功",                    });                    return;                }
                try {                    const res = JSON.parse(xhr.responseText);                    resolve({                        code: 1,                        info: res,                        msg: "成功",                    });                } catch (error) {                    resolve({                        code: 0,                        info: error,                        msg: "失敗",                    });                }            };
            // 如果當前的請求方式為 POST, 那么需要配置上對應的 請求頭            if (/^(POST)$/i.test(_options.method)) {                xhr.setRequestHeader(                    "content-type",                    _options.headers["content-type"]                );            }            // 如果 authorization 內有值, 需要帶上 authorization            if (_options.headers.authorization) {                xhr.setRequestHeader(                    "authorization",                    _options.headers.authorization                );            }            // 3.4 發送本次請求            /^(POST)$/i.test(_options.method)                ? xhr.send(_options.data)                : xhr.send();        });        return p;    }
    return ajax;}
const res = outer("http://localhost:8888");
res({    url: "/test/first",}).then(res => {    console.log(res)});
res({    url: "/test/second",    dataType: 'json'}).then(res => {    console.log(res)});

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/38932.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/38932.shtml
英文地址,請注明出處:http://en.pswp.cn/news/38932.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java技術整理(5)—— Spring篇

Spring是一個全面的全面的、企業應用開發一站式的解決方案,貫穿表現層、業務層、持久層。但是 Spring 仍然可以和其他的框架無縫整合。 1、Spring的核心組件 (1)數據層: JDBC、ORM、OXM、JMS、Transations (2&#x…

Flutter 中,ListView 中需要放置 ListView 需要怎么處理才高效?

問題及場景 ListView 是 Flutter 開發者第一個學習到的 Widget,因為它可以滑動。一切都會運行得很好,直到 ListView 中的 Item 本身也是一個 ListView。你可能會看到 Flutter 建議你將內部的 ListView 的ShrinkWrap 屬性設置為 True。雖然錯誤消除了&am…

連續兩年增收不增利,比亞迪電子靠新能源汽車業務再次起飛?

在凈利潤連續兩年下挫之后,比亞迪電子(00285.HK)終于迎來了好消息。 不久前比亞迪電子發布2023年中期盈利預告顯示,上半年凈利潤同比增加115%-146%(2022年上半年的凈利潤顯示6.34億元)。 這主要受益于大客…

包管理工具 nvm npm nrm yarn cnpm npx pnpm詳解

包管理工具 nvm npm yarn cnpm npx pnpm npm、cnpm、yarn、pnpm、npx、nvm的區別:https://blog.csdn.net/weixin_53791978/article/details/122533843 npm、cnpm、yarn、pnpm、npx、nvm的區別:https://blog.csdn.net/weixin_53791978/article/details/1…

【Freertos基礎入門】2個Freertos的Delay函數

文章目錄 前言一、vTaskDelay與vTaskDelayUntil二、示例代碼總結 前言 本系列基于stm32系列單片機來使用freerots 任務管理是實時操作系統(RTOS)的核心功能之一,它允許開發者以并發的方式組織和管理多個任務。FreeRTOS 是一個流行的開源RTO…

嵌入式開發中常用且雜散的命令

1、mount命令 # 掛載linux系統 mkdir /tmp/share mount -t nfs 10.77.66.88:/share/ /tmp/share -o nolock,tcp cd /tmp/share# 掛載Windows系統 mkdir /tmp/windows mount -t nfs 10.66.77.88:/c/public /tmp/windows -o nolock,tcp cd /tmp/windows# 掛載vfat格式的U盤 mkdi…

強訓第32

選擇 D B A A 發送TCP意思應該是已經建立了連接,會超時重傳。在未建立連接的時候,會放棄該鏈接 C A 80端口是http A 交換機攻擊主要有五種:VLAN跳躍攻擊 生成樹攻擊 MAC表洪水攻擊 ARP攻擊 VTP攻擊 B A 2^(32-26)2^(32-27)2^(32-27)128 減去…

基于Java+SpringBoot+Vue+echarts健身房管理系統設計和實現

博主介紹:?全網粉絲30W,csdn特邀作者、博客專家、CSDN新星計劃導師、Java領域優質創作者,博客之星、掘金/華為云/阿里云/InfoQ等平臺優質作者、專注于Java技術領域和畢業項目實戰? 🍅文末獲取源碼聯系🍅 👇🏻 精彩專…

maven Jar包反向install到本地倉庫

maven Jar包反向install到本地倉庫 需求實現 需求 項目打包時報錯,缺少一個jar包。 但是在maven倉庫都找不到此jar包,其他人提供了這個jar包。 需要把這個jar包install到本地倉庫,使項目能正常打包運行。 實現 使用git bash命令執行以下腳…

16.3.4 【Linux】系統資源的觀察

free :觀察內存使用情況 系統當中有 2848MB 左右的實體內存,我的 swap 有 1GB 左右, 那我使用free -m 以 MBytes 來顯示時,就會出現上面的信息。Mem 那一行顯示的是實體內存的量,Swap 則是內存交換空間的量。 total 是…

C++多態

文章目錄 🐵1. 什么是多態🐶2. 構成多態的條件🐩2.1 虛函數🐩2.2 虛函數的重寫🐩2.3 final 和 override關鍵字🐩2.4 重載、重寫、重定義對比 🐱3. 虛函數表🐯4. 多態的原理&#x1f…

神經網絡基礎-神經網絡補充概念-17-計算神經網絡的輸出

計算神經網絡的輸出通常涉及前向傳播(Forward Propagation)的過程,其中輸入數據通過網絡的層級結構,逐步被傳遞并變換,最終生成預測結果。下面我將為你展示一個簡單的神經網絡前向傳播的示例。 假設我們有一個具有以下…

【變形金剛01】attention和transformer所有信息

圖1.來源:Arseny Togulev在Unsplash上的照片 一、說明 這是一篇 長文 ,幾乎討論了人們需要了解的有關注意力機制的所有信息,包括自我注意、查詢、鍵、值、多頭注意力、屏蔽多頭注意力和轉換器,包括有關 BERT 和 GPT 的一些細節。因…

OpenCV圖像處理——輪廓檢測

目錄 圖像的輪廓查找輪廓繪制輪廓 輪廓的特征輪廓面積輪廓周長輪廓近似凸包邊界矩形最小外接圓橢圓擬合直線擬合 圖像的矩特征矩的概念圖像中的矩特征 圖像的輪廓 查找輪廓 binary,contours,hierarchycv.findContours(img,mode,method)繪制輪廓 cv.drawContours(img,coutours…

WSL2安裝Ubuntu,配置機器學習環境

文章目錄 1.WSL2安裝Ubuntu,更改安裝位置,作為開發環境供vscode和pycharm使用:2.更換國內源:3.安裝圖形界面:4.安裝cudacudnntorch5.安裝opencv6.調用攝像頭7.使用yolov8測試 WSL全稱Windows Subsystem for Linux&…

印度貨代專線【我國到印度專線有哪些方式】

隨著全球貿易的不斷發展,我國與印度之間的貿易往來也日益頻繁。作為兩個人口最多的國家之一,中國和印度之間的貨物運輸需求不斷增長。為了滿足這一需求,印度貨代專線應運而生,為進出口商提供高效、可靠的貨物運輸服務。本文將探索…

939. 最小面積矩形;2166. 設計位集;2400. 恰好移動 k 步到達某一位置的方法數目

939. 最小面積矩形 核心思想:枚舉矩形的右邊那條邊的兩個點,并用一個哈希表存儲相同縱坐標的最近出現的列的列數,不斷更新最近出現的左邊那條邊。 2166. 設計位集 核心思想:這題主要是時間復雜度的優化,用一個flag來標記當前翻轉…

CSS自學框架之表單

首先我們看一下表單樣式,下面共有5張截圖 一、CSS代碼 /*表單*/fieldset{border: none;margin-bottom: 2em;}fieldset > *{ margin-bottom: 1em }fieldset:last-child{ margin-bottom: 0 }fieldset legend{ margin: 0 0 1em }/* legend標簽是CSS中用于定義…

IOS開發-XCode14介紹與入門

IOS開發-XCode14介紹與入門 1. XCODE14的小吐槽2. XCODE的功能bar一覽3. XCODE項目配置一覽4. XCODE更改DEBUG/RELEASE模式5. XCODE單元測試 1. XCODE14的小吐槽 iOS開發工具一直有個毛病,就是新版本的開發工具的總會有一些奇奇怪怪的bug。比如在我的Mac-Pro&#…

Springboot 實踐(3)配置DataSource及創建數據庫

前文講述了利用MyEclipse2019開發工具,創建maven工程、加載springboot、swagger-ui功能。本文講述創建數據庫,為項目配置數據源,實現數據的增刪改查服務,并通過swagger-ui界面舉例調試服務控制器 創建數據庫 項目使用MySQL 8.0.…