原生JS发送异步数据请求

栏目: Json · 发布时间: 7年前

内容简介:原生JS发送异步数据请求

在做项目的时候,有时候需要用到异步数据请求,但是如果这个时候没有框架的依赖,就需要用到原生JS进行异步数据请求。这时候无非有两种请求方式,一种是AJAX,另一个是JSONP。通过原生JS对异步请求进行简单的封装。

AJAX

AJAX是一种数据请求方式,不需要刷新整个页面就能够更新局部页面的数据。AJAX的技术核心是XMLHttpRequest对象,主要请求过程如下:

  1. 创建XMLHttpRequest对象(new)
  2. 连接服务器(open)
  3. 发送请求(send)
  4. 接收响应数据(onreadystatechange)

不说话直接贴代码

/**
* 通过JSON的方式请求
* @param  {[type]} params [description]
* @return {[type]}        [description]
*/
ajaxJSON(params) {
    params.type = (params.type || 'GET').toUpperCase();
    params.data = params.data || {};
    var formatedParams = this.formateParams(params.data, params.cache);
    var xhr;
    //创建XMLHttpRequest对象
    if (window.XMLHttpRequest) {
        //非IE6
        xhr = new XMLHttpRequest();
    } else {
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    }
    //异步状态发生改变,接收响应数据
    xhr.onreadystatechange = function(){
        if (xhr.readyState == 4 && xhr.status == 200) {
            if (!!params.success) {
                if (typeof xhr.responseText == 'string') {
                    params.success(JSON.parse(xhr.responseText));
                } else {
                    params.success(xhr.responseText);
                }
            }
        } else {
            params.error && params.error(status);
        }
    }
    if (params.type == 'GET') {
        //连接服务器
        xhr.open('GET', (!!formatedParams ? params.url + '?' + formatedParams : params.url), true);
        //发送请求
        xhr.send();
    } else {
        //连接服务器
        xhr.open('POST', params.url, true);
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        //发送请求
        xhr.send(formatedParams);
    }
},
/**
* 格式化数据
* @param  {Obj}     data    需要格式化的数据
* @param  {Boolean} isCache 是否加入随机参数
* @return {String}          返回的字符串
*/
formateParams: function(data, isCache){
    var arr = [];
    for (var name in data) {
        arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));
    }
    if (isCache) {
        arr.push('v=' + (new Date()).getTime());
    }
    return arr.join('&');
}

IE7及其以上版本中支持原生的 XHR 对象,因此可以直接用: var oAjax = new XMLHttpRequest(); 。IE6及其之前的版本中,XHR对象是通过MSXML库中的一个ActiveXObject对象实现的。

通过xhr的open函数来连接服务器,主要接收三个参数:请求方式、请求地址和是否异步请求(一般都是异步请求)。请求方式有两种,GET和POST,GET是通过URL将数据提交到服务器的,POST则是通过将数据作为send方法的参数发送到服务器。

给xhr绑定状态改变函数onreadystatechange,主要用来检测xhr的readyState的变化,当异步发送成功后,readyState的数值会由0变成4,同时触发onreadystatechange事件。readyState的属性及对应状态如下:

  • 0 (未初始化) 对象已建立,但是尚未初始化(尚未调用open方法)
  • 1 (初始化) 对象已建立,尚未调用send方法
  • 2 (发送数据) send方法已调用,但是当前的状态及http头未知
  • 3 (数据传送中) 已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误
  • 4 (完成) 数据接收完毕,此时可以通过通过responseBody和responseText获取完整的回应数据

在readystatechange事件中,先判断响应是否接收完成,然后判断服务器是否成功处理请求,xhr.status 是状态码,状态码以2开头的都是成功,304表示从缓存中获取,上面的代码在每次请求的时候都加入了随机数,所以不会从缓存中取值,故该状态不需判断。

JSONP

如果还是用上面的XMLHttpRequest对象来发送需要跨域的请求,虽然调用了send函数,但是xhr的状态一直都是0,也不会触发onreadystatechange事件,这个时候就要用到JSONP的请求方式了。

JSONP(JSON with Padding) 是一种跨域请求方式。主要原理是利用了script标签可以跨域请求的特点,由其 src 属性发送请求到服务器,服务器返回js代码,网页端接受响应,然后就直接执行了,这和通过script标签引用外部文件的原理是一样的。

JSONP由两部分组成:回调函数和数据,回调函数一般是由网页端控制,作为参数发往服务器端,服务器端把该函数和数据拼成字符串返回。

比如网页端创建一个script标签,并给其src赋值为 http://www.test.com/json/?callback=process, 此时网页端就发起一个请求。服务端将要返回的数据拼作为函数的参数传入,服务端返回的数据格式类似”process({‘name:’xieyufei’})”,网页端接收到了响应值,因为请求者是 script,所以相当于直接调用process方法,并且传入了一个参数。

不说话直接贴代码。

/**
* 通过JSONP的方式请求
* @param  {[type]} params [description]
* @return {[type]}        [description]
*/
ajaxJSONP(params) {
    params.data = params.data || {};
    params.jsonp = params.jsonp || 'callback';

    // 设置传递给后台的回调参数名和参数值
    var callbackName = 'jsonp_' + (new Date()).getTime();
    params.data[params.jsonp] = callbackName;
    var formatedParams = this.formateParams(params.data, params.cache);

    //创建script标签并插入到页面中
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    head.appendChild(script);

    //创建jsonp回调函数
    window[callbackName] = function(json){
        head.removeChild(script);
        clearTimeout(script.timer);
        window[callbackName] = null;
        params.success && params.success(json);
    };

    //发送请求
    script.src = (!!formatedParams ? params.url + '?' + formatedParams : params.url);

    //为了得知此次请求是否成功,设置超时处理
    if (params.time) {
        script.timer = setTimeout(function(){
            window[callbackName] = null;
            head.removeChild(script);
            params.error && params.error({
                message: '超时'
            });
        }, params.time);
    }
}

给script标签设置src属性时浏览器就会去发送请求,但是只能发送一次请求,导致script标签不能复用,因此每次操作完都需要把script标签移除。在浏览器发送请求之前给全局绑定一个回调函数,当数据请求成功时就会调用这个回调函数。

总结

将两种发送异步数据的方式整合起来,根据dataType来进行判断选用哪种方式。贴上完整的代码

var xyfAjax = {
    ajax: function(params){
        params = params || {};
        params.cache = params.cache || false;

        if (!params.url) {
            throw new Error('参数不合法');
        }
        params.dataType = (params.dataType || 'json').toLowerCase();
        if (params.dataType == 'jsonp') {
            this.ajaxJSONP(params);
        } else if (params.dataType == 'json') {
            this.ajaxJSON(params);
        }

    },
    /**
    * 通过JSONP的方式请求
    * @param  {[type]} params [description]
    * @return {[type]}        [description]
    */
    ajaxJSONP(params) {
        params.data = params.data || {};
        params.jsonp = params.jsonp || 'callback';

        // 设置传递给后台的回调参数名和参数值
        var callbackName = 'jsonp_' + (new Date()).getTime();
        params.data[params.jsonp] = callbackName;
        var formatedParams = this.formateParams(params.data, params.cache);

        //创建script标签并插入到页面中
        var head = document.getElementsByTagName('head')[0];
        var script = document.createElement('script');
        head.appendChild(script);

        //创建jsonp回调函数
        window[callbackName] = function(json){
            head.removeChild(script);
            clearTimeout(script.timer);
            window[callbackName] = null;
            params.success && params.success(json);
        };

        //发送请求
        script.src = (!!formatedParams ? params.url + '?' + formatedParams : params.url);

        //为了得知此次请求是否成功,设置超时处理
        if (params.time) {
            script.timer = setTimeout(function(){
                window[callbackName] = null;
                head.removeChild(script);
                params.error && params.error({
                    message: '超时'
                });
            }, params.time);
        }
    },
    /**
    * 通过JSON的方式请求
    * @param  {[type]} params [description]
    * @return {[type]}        [description]
    */
    ajaxJSON(params) {
        params.type = (params.type || 'GET').toUpperCase();
        params.data = params.data || {};
        var formatedParams = this.formateParams(params.data, params.cache);
        var xhr;

        //创建XMLHttpRequest对象
        if (window.XMLHttpRequest) {
            //非IE6
            xhr = new XMLHttpRequest();
        } else {
            xhr = new ActiveXObject('Microsoft.XMLHTTP');
        }

        //异步状态发生改变,接收响应数据
        xhr.onreadystatechange = function(){
            if (xhr.readyState == 4 && xhr.status == 200) {
                if (!!params.success) {
                    if (typeof xhr.responseText == 'string') {
                        params.success(JSON.parse(xhr.responseText));
                    } else {
                        params.success(xhr.responseText);
                    }
                }
            } else {
                params.error && params.error(status);
            }
        }

        if (params.type == 'GET') {
            //连接服务器
            xhr.open('GET', (!!formatedParams ? params.url + '?' + formatedParams : params.url), true);
            //发送请求
            xhr.send(null);
        } else {
            //连接服务器
            xhr.open('POST', params.url, true);
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            //发送请求
            xhr.send(formatedParams);
        }

    },
    /**
    * 格式化数据
    * @param  {Obj}     data    需要格式化的数据
    * @param  {Boolean} isCache 是否加入随机参数
    * @return {String}          返回的字符串
    */
    formateParams: function(data, isCache){
        var arr = [];
        for (var name in data) {
            arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));
        }
        if (isCache) {
            arr.push('v=' + (new Date()).getTime());
        }
        return arr.join('&');
    }
}

xyfAjax.ajax({
    url:'http://www.xieyufei.com',
    type:'get', //or post
    dataType:'json', //or jsonp
    data:{
        name:'xyf'
    },
    success: function(data){
        console.log(data)
    }
})

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

A Common-Sense Guide to Data Structures and Algorithms

A Common-Sense Guide to Data Structures and Algorithms

Jay Wengrow / Pragmatic Bookshelf / 2017-8-13 / USD 45.95

If you last saw algorithms in a university course or at a job interview, you’re missing out on what they can do for your code. Learn different sorting and searching techniques, and when to use each. F......一起来看看 《A Common-Sense Guide to Data Structures and Algorithms》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具