zoukankan      html  css  js  c++  java
  • JavaScript:原生模拟$.ajax以及jsonp

    现实项目中,常常会用到请求,但是在考虑低版本的浏览器时,promise相关的axios,fetch这类第三方库的支持率就不那么好了,再考虑到最大的一个问题,跨域,更是让人头痛,虽然也有fetch-jsonp的方案,但是引入过多的库反而让项目变得复杂,后期插件版本升级等就比较繁琐。最常用的也是曾经红极一时的,那一定是jQuery或者zepto的$.ajax方案了,完美兼容多平台浏览器及低版本,支持jsonp跨域等,但是在现在大多数项目已不再用jQuery或zepto来实现开发,大多数用的是React,vue等前端库,所以如果仅仅为了一个ajax就引入一个库,未免有点浪费,所以,最好还是自己封装一个ajax函数,来模仿jQuery的$.ajax。

    先看一下实现后的使用案例:

    第一种,普通请求:

    ajax({  
     url: 'test.php',  // 请求地址
     type: 'POST',  // 请求类型,默认"GET",还可以是"POST"
     data: {'b': '异步请求'},  // 传输数据
     success: function(res){  // 请求成功的回调函数
      console.log(JSON.parse(res));  
     },
     error: function(error) {}  // 请求失败的回调函数
    });

    第二种,跨域请求:

    ajax({  
      url: 'test',  // 请求地址
     jsonp: 'jsonpCallback', // 采用jsonp请求,且回调函数名为"jsonpCallbak",可以设置为合法的字符串
     data: {'b': '异步请求'},  // 传输数据
     success:function(res){  // 请求成功的回调函数
      console.log(res);  
     },
     error: function(error) {}  // 请求失败的回调函数
    });

    可以看出,都是用了ajax()这个方法,用法就跟jQuery的$.ajax一样,那如何实现?

    不多说,直接上代码:

    function ajax(params) {
        params = params || {};
        params.data = params.data || {};
        var json = params.jsonp ? jsonp(params) : json(params);
    }
    
    function json(params) {
        params.type = (params.type || 'GET').toUpperCase();
        params.data = formatParams(params.data);
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
            if (xhr.readyState == 4) {
                var status = xhr.status;
                if (status >= 200 && status < 300) {
                    var type = xhr.getResponseHeader('Content-Type');
                    if (type.indexOf('xml') !== -1 && xhr.responseXML) {
                        // document 对象响应
                        var response = xhr.responseXML;
                    } else if (type == 'application/json') {
                        // JSON响应
                        var response = JSON.parse(xhr.responseText);
                    } else {
                        // 字符串响应
                        var response = xhr.responseText;
                    }
              params.success && params.success(response);
                } else {
                    params.error && params.error(status);
                }
            }
        }
        if (params.type == 'GET') {
            xhr.open('GET', params.url + '?' + params.data, true);
            xhr.send(null);
        } else {
            xhr.open(params.type, params.url, true);
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');         
            xhr.send(params.data);
        }
    }
    
    function jsonp(params){
        var callbackName = params.jsonp;
        var head = document.getElementsByTagName('head')[0];
        params.data['callback'] = callbackName;
        params.data = formatParams(params.data);
        var script = document.createElement('script');
        head.appendChild(script);
        window[callbackName] = function(json){
            head.removeChild(script);
            window[callbackName] = null;
            clearTimeout(script.timer);
            params.success && params.success(json)
        }
        script.url = params.url + '?' + params.data;
        // 设置超时限制
        if (params.time) {
            script.timer = setTimeout(function(){
                window[callbackName] = null;
                clearTimeout(script.timer);
                head.removeChild(script);
                params.error && params.error({
                    message: '超时'
                });
            }, params.time);
        }
    }
    
    function formatParams(data) {
        var arr = [];
        for (var name in data) {
            arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]))
        }
        // 添加随机数,防止缓存
        arr.push('v=' + random());
        return arr.join('&')
    }
    
    function random(){
        return Math.floor(Math.random * 10000 + 500)
    }
    

      

     这里有几个要注意的点:

    1,参数为空的处理;

    2,如果是非jsonp,在监听onreadyStateChange事件时,针对成功请求的结果,还要分情况处理返回值,根据Content-Type后面的值来讨论;

    3,发送请求的时候,如果是非GET请求,需要设置请求头;

    4,如果是jsonp,在调用回调的时候,一定要做内存清理、定时器清理等,保证性能;

    5,数据格式化的时候,要用encodeURIComponent来处理,除了中间的=号,键和值都要处理,然后在末尾要添加随机数,防止缓存;

    end

  • 相关阅读:
    struts2 s:if 的字符串比较问题
    struts2 标签
    servlet filter
    div滚动与控制
    页面定位
    linux下编译利用CMakeLists.txt 编译C++写的opencv程序
    yolo image.c
    强制杀进程
    PDB GDB 调试代码
    YOLOv3的Darknet在OpenCV3.4.1(bug)下编译出错填坑
  • 原文地址:https://www.cnblogs.com/yanchenyu/p/8491917.html
Copyright © 2011-2022 走看看