使用 ES6 Promise 对 jQuery.ajax 方法进行简易封装

使用 ES6 Promise 对 jQuery.ajax 方法进行简易封装

日常开发业务中我们经常会遇到几个接口需要同步调用的情况,举个例子:

  • 页面发起请求到 接口1 获取本机的 外网ip
  • 获取到 外网ip 后,又需要请求 接口2 查询 运营商、归属地 等信息
  • 同时页面有另一个无关上面两个的数据需求,需要请求 接口3

项目中使用 $.ajax 去请求接口,最简单粗暴的方式其实就是把 {"async": true} 这个默认值改为 false

$.ajax({
    url: 'http://domain-requested:port/api/endpoint',
    type: 'GET',
    data: {},
    dataType: 'json',
    async: false,
    success: function (data, status) {
        //前端需要对data做的操作写在这个回调里
    },
    error: function (XMLHttpRequest, textStatus, errThrown) {
        //请求失败的情况处理写在这个回调里
    }
});

但是这样一来,所有的接口都是同步请求的,如果这个页面有非常多的请求需要执行,那么响应速度不是就很慢吗?于是我想到了 ES6 Promise 的写法。

非专业前端开发,编码技术拙劣,仅做记录供以后参考。请多指点交流

代码如下:

/**
  * 通用请求方法($.ajax, Promise)
  * @param url 请求地址
  * @param options 请求参数
  * @return ECMAScript 6 Promise对象
  */
function request(url, options={}) {
    //Promise相关知识还请自行查阅,这里只给个大致思路
    return new Promise((resolve, reject) => {
        try {
            //从cookie里拿令牌给服务端鉴权
            //这个getCookie不是内置的方法,但网上有很多类似的
            const token = getCookie('token');
            const reqOptions = {
                url: '',
                type: 'GET',
                data: {},
                dataType: 'json',
                async: true,
                contentType: 'application/x-www-form-urlencoded',
                headers: {
                    Authorization: `Bearer ${token}`,
                },
                complete: function (XMLHttpRequest, textStatus) {
                    //complete回调是只要请求结束就执行
                    //一般业务中这里可能会需要关闭页面上的loading遮罩之类的操作
                    if (!!options.complete && typeof options.complete === "function") {
                        options.complete(XMLHttpRequest, textStatus);
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    //error回调是请求发生错误时会进来
                    //需要注意服务端返回形如{"code": 500}的报文,但HTTP响应码依然为200的这种不会进来的
                    console.log(`'${url}' request failed: ${textStatus}`);
                    if (!!options.error && typeof options.error === "function") {
                        options.error(XMLHttpRequest, textStatus, errorThrown);
                    }
                    //reject出去的对象,在promise.catch里可以拿到
                    reject({
                        'url': url,
                        'xhr': XMLHttpRequest,
                        'status': textStatus,
                        'error': errorThrown,
                    });
                },
                success: function (data, textStatus, jqXHR) {
                    //success回调时请求成功时执行
                    if (!!options.success && typeof options.success === "function") {
                        options.success(data, textStatus, jqXHR);
                    }
                    //resolve出去的对象,在promise.then里可以拿到
                    resolve({
                        'url': url,
                        'data': data,
                        'status': textStatus,
                        'xhr': jqXHR,
                    });
                },
            };
            if (!token || token === 'undefined' || token === 'null') {
                delete reqOptions.headers.Authorization;
            }
            //用自定义options扩展默认options,去调用jQuery.ajax
            $.ajax($.extend({}, reqOptions, $.extend({}, options, {'url': url})));
        } catch (error) {
            //做个异常处理,把错误信息reject出去
            reject({
                'url': url,
                'error': error,
            });
        }
    });
}

调用案例:

$(document).ready(function () {
    // 模拟业务:先获取ip再获取运营商信息 对接口2来说ip是必要参数
    getIpAddrLocation().then(result => {
        console.log(`获取到当前ip为: ${result.data.ip}`);
        getISP(result.data.ip).then(res => {
            console.log(`获取到ip:'${result.data.ip}'的运营商信息: '${JSON.stringify(res.data)}'`);
        }).catch(err => {
            console.log(`获取到ip:'${result.data.ip}'的运营商信息时错误: '${err.error}'`);
        });
    }).catch(err => {
        console.log(`获取到当前ip时出错: ${err.error}`);
    });

    // 模拟:和ip不相关的业务 不管上面两个完成没有都异步获取
    getLocalResp().then(result => {
        console.log(`异步获取和ip无关的json报文:${JSON.stringify(result.data)}`);
    }).catch(err => {
        console.log(`异步获取和ip无关的json报文时出错: ${err.error}`);
    });
});

/**
  * 模拟获取本地响应,和其他业务无关的接口调用
  * @return Promise
  */
async function getLocalResp() {
    const url = 'http://localhost/frontend/mock/json_wrap.json';
    return await request(url);
}

/**
  * 模拟获取ip和一些其他的基本信息
  * @return Promise
  */
async function getIpAddrLocation() {
    //这里接口用nginx做了转发,不然localhost走外部接口会报跨域问题
    const url = 'http://localhost/whois-pconline/ipJson.jsp';
    return await request(url, {
        data: {
            json: true,
        }
    });
}

/**
  * 模拟通过ip获取运营商等信息
  * @return Promise
  */
async function getISP(ipaddr='') {
    //这里接口用nginx做了转发,不然localhost走外部接口会报跨域问题
    //const url = 'http://localhost/ip-taobao/service/getIpInfo.php';
    const url = 'http://localhost/whois-pconline/ipJson.jsp';
    return await request(url, {
        data: {
            ip: ipaddr,
            json: true,
        }
    });
}

执行结果如下:

执行结果

接口请求顺序如下:

请求顺序

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值