JavaScript全解析——Ajax(下)

Ajax(下)

●http 传输协议

○http(s) 协议规定了, 只能由前端主动发起
○并且在传输的过程中, 只能传递 字符串

●http 协议过程

1.建立连接

浏览器和服务器进行连接建立
基于 TCP/IP 协议的三次握手

2.发送请求

要求前端必须以 请求报文 的形式发送

报文由浏览器组装, 我们只需要提供对应的信息即可

报文包含的内容

请求报文行
请求方式, 请求地址, 传输协议
请求报文头(对本次请求的一些说明信息)
userAgent: 请求方终端信息
accept: 期望后端返回的数据类型
content-type: 请求携带的 "材料" 的数据格式
  cookie: 只要 cookie 空间内有内容, 会自动携带
  请求报文空行
  请求报文体(不是所有请求都有)

3.接收响应

要求后端必须以响应报文的形式返回
报文由服务器组装
响应报文包含的内容
响应报文行
响应状态码, 简单信息描述响应状态码, 传输协议
响应报文头(对本次响应的一些说明信息)
server: 哪一个服务器给你返回的信息
date: 时间, 服务器时间
content-length: 响应体长度
content-type: 响应数据类型
响应报文体(后端返回给前端的一些信息)

4.断开连接

浏览器和服务器断开连接
基于 TCP/IP 协议的四次挥手
●响应状态码
○100199 表示连接继续
○200299 表示各种成功
○300399 表示重定向
○400499 表示各种客户端错误
○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. all
Promise.all([fn(), fn(), fn()])
    .then(function () {
        console.log("所有的 参数 都返回 成功状态");
    })
    .catch(function () {
        console.log("这些参数中, 有一个 为 失败状态");
    });
// 2. race
Promise.race([fn(), fn(), fn()])
    .then(function () {
        console.log("速度最快的那个执行完毕, 并且是成功状态时 执行");
    })
    .catch(function () {
        console.log("速度最快的那个执行完毕, 并且是失败状态时 执行");
    });
// 3. allSettled
Promise.allSettled([fn(), fn(), fn()])
    .then(function (res) {
        console.log(res);
    })
    .catch(function (res) {
        console.log(res);
    });
// 4. resolve
Promise.resolve()
    .then(function (res) {
        console.log("成功");
    })
    .catch(function (res) {
        console.log("失败");
    });
// 5. reject
Promise.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)
});

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值