美文网首页
[JS] 原生Ajax函数

[JS] 原生Ajax函数

作者: w_w_wei | 来源:发表于2018-07-05 19:55 被阅读0次
    /**
     * ajax和跨域jsonp
     * Created by xgx on 2015-10-08.
     *
     * @param {string} url
     * @param {Object} options
     *          {string} type 请求方式
     *              default: GET
     *              GET | POST
     *          {string | Object} data 数据
     *              可以是对象或构造好的字符串
     *          {bool} crossDomain 是否跨域
     *              跨域则使用jsonp异步方式
     *          {int} timeout  超时时间
     *              单位ms
     *              default: 60 000
     *          {Function} error 失败回调
     *          {Function} success 成功回调
     *          {Function} resultFilter 结果过滤
     *              根据结果来判断成功失败, 用来处理通用的已知错误, 仅支持jsonp
     *          {Function} complete 请求完成后回调
     *              无论成功失败均会执行
     *          {string} jsonpCallback
     *              default: EA_cb + 自增值
     *          {string} jsonp  回调函数字段名
     *              default: callback,
     *          {bool} async 是否异步
     *              默认为异步
     *              default: true, force true for crossDomain 'true'
     *          {bool} cache 缓存
     *              false仅在type 'GET' 时有效
     *              default: true
     *          {string} dataType 数据类型
     *              json时会自动解析, script时会自动执行
     *              default: xml,
     *              xml | json | script
     */
    function ajax(url, options) {
        //异步请求回调函数序号,从10000开始自增
        this.jsonpIndex = this.jsonpIndex || 10000;
        options = options || {};
        options = {
            type: options.type || "GET",
            data: options.data || "",
            complete: options.complete || new Function(),
            error: options.error || new Function(),
            success: options.success || new Function(),
            resultFilter: options.resultFilter || new Function(),
            //默认1min超时
            timeout: options.timeout || 1000 * 60,
    
            //jsonp
            crossDomain: options.crossDomain || false,
            jsonpCallback: options.jsonpCallback || "EA_cb" + this.jsonpIndex,
            jsonp: options.jsonp || "callback",
    
            //默认为异步
            async: typeof(options.async) === "undefined" ? true : options.async,
            cache: typeof(options.cache) === "undefined" ? true : options.cache,
            dataType: options.dataType || ""
        };
    
        //处理data
        var dataString = "";
        if (typeof (options.data) === "object") {
            for (var x in options.data) {
                if (options.data.hasOwnProperty(x)) {
                    dataString += "&" + x + "=" + encodeURIComponent(options.data[x]);
                }
            }
            options.data = dataString.substr(1);
        }
        //GET & JSONP 都通过URL传data
        if (options.data && (options.type === "GET" || options.crossDomain)) {
            url += (url.indexOf("?") !== -1) ? "&" : "?";
            url += options.data;
        }
    
        //处理跨域请求
        if (options.crossDomain) {
            this.jsonpIndex++;
            return jsonp(url, options);
        }
    
        //处理缓存
        if (!options.cache && options.type === "GET") {
            url += (url.indexOf("?") !== -1) ? "&" : "?";
            url += "_=" + Math.random().toString().substr(2);
        }
    
        if (typeof XMLHttpRequest === "undefined") {
            XMLHttpRequest = function () {
                var xmlhttp;
                if (window.ActiveXObject) {
                    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
                    if (!xmlhttp) {
                        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
                    }
                } else {
                    alert("Init XMLHTTP Error!");
                }
                return xmlhttp;
            }
        }
    
        var xml = new XMLHttpRequest();
        xml.open(options.type, url, options.async);
    
        var requestDone = false;
        window.setTimeout(function () {
            if (requestDone) {
                return;
            }
            requestDone = true;
            options.error();
        }, options.timeout);
    
        //监听文档状态的改变
        xml.onreadystatechange = function () {
            if (xml.readyState == 4 && !requestDone) {
                requestDone = true;
                if (httpSuccess(xml)) {
                    options.success(httpData(xml, options.dataType));
                }
                else {
                    options.error(xml, xml.status, xml.statusText);
                }
                options.complete();
                //为避免内存泄漏,清理文档
                xml = null;
            }
        };
    
        //header
        xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    
        try {
            if (options.data) {
                xml.send(options.data);
            }
            else {
                xml.send(null);
            }
        }
        catch (e) {
            return null;
        }
    
        //JSONP跨域请求
        function jsonp(url, options) {
            var timeout_trigger = window.setTimeout(function () {
                window[options.jsonpCallback] = new Function();
                console.error("JSONP: Connect timeout: ", options.timeout);
                options.error();
                //清空,防止超时和出错时重复调用
                options.error = new Function();
                options.complete();
                options.complete = new Function();
                removeDom(options.jsonpCallback);
            }, options.timeout);
            var json;
            url += (url.indexOf("?") !== -1) ? "&" : "?";
            url += options.jsonp + "=" + options.jsonpCallback;
            window[options.jsonpCallback] = function (data) {
                window.clearTimeout(timeout_trigger);
                options.complete();
                if (options.dataType == "json") {
                    if (!data.length) {
                        console.error("JSONP: Json data is Empty , On URL : ", url);
                        options.error();
                        return;
                    }
                    try {
                        json = JSON.parse(data);
                    } catch (e) {
                        //json解析异常
                        console.error(
                            "JSONP: Json data parse error : ", e, ", data is : ", data, ", On URL : ", url
                        );
                        options.error();
                        return;
                    }
                    if (options.resultFilter(json)) {
                        options.error();
                    } else {
                        options.success(json);
                    }
                } else {
                    options.success(data);
                }
                removeDom(options.jsonpCallback);
            };
            var script = document.createElement("script");
            script.id = options.jsonpCallback;
            script.type = "text/javascript";
            script.async = true;
            script.onerror = function () {
                console.error("JSONP: Network Connect error!");
                window.clearTimeout(timeout_trigger);
                options.error();
                options.error = new Function();
                removeDom(options.jsonpCallback);
            };
            script.src = url;
            document.getElementsByTagName("head")[0].appendChild(script);
        }
    
        //删除指定Script标签
        function removeDom(id) {
            setTimeout(function () {
                var dom = $ID(id);
                if (dom) {
                    document.getElementsByTagName("head")[0].removeChild(dom);
                }
                //30s 后再清除, 避免出现加载问题
            }, 30000);
        }
    
        //判断http响应是否成功
        function httpSuccess(r) {
            try {
                return (!r.status && location.protocol == "file:") ||
                    (r.status >= 200 && r.status < 300) ||
                    r.status == 304 ||
                    (navigator.userAgent.indexOf("Safari") >= 0 &&
                    r.status === undefined);
            }
            catch (e) {
            }
            return false;
        }
    
        //从http响应中解析得到正确的数据
        function httpData(r, type) {
            var ct = r.getResponseHeader("Content-Type");
            type = !type ? (ct.indexOf("xml") >= 0 ? "xml" : "") : type;
            var data = type == "xml" ? r.responseXML : r.responseText;
            if (type == "script") {
                eval.call(window, data);
            }
            if (type == "json") {
                try {
                    data = JSON.parse(data);
    
                } catch (e) {
                    //json解析异常
                    console.error(
                        "JSONP: Json data parse error : ", e, ", data is : ", data, ", On URL : ", url
                    );
                    options.error();
                    return;
                }
            }
            return data;
        }
    }
    

    相关文章

      网友评论

          本文标题:[JS] 原生Ajax函数

          本文链接:https://www.haomeiwen.com/subject/efboyftx.html