二、ajax

2017-02-25  本文已影响57人  sheepmiee

认识AJAX

扫盲1:

AJAX: Asynchronous Javascript And XML
html: 超文本标记语言,W3C指定了很多具有语义化的标记标签,用以搭建页面结构(目前多用V4/V5版本)
xhtml: 更加严谨的html
dhtml: 页面中的数据是动态绑定的
xml: 可扩展的标记标签语言,它里面使用的标签都是自己定义的,用来存储数据,结构清晰,以前用的比较多,不过其二次解析的过程相对JSON比较麻烦,目前前端数据多用JSON

   <root>
       <student>
           <name>唐玄奘</name>
           <age>18</age>
       </student>
   </root>

wxml: 微信小程序的页面就是.wxml,小程序中使用的标签都是小程序自己定义的(微信XML)

扫盲2:

这里的异步不能理解为JS中的同步异步编程,这里面的异步指的是‘局部刷新’,如果用六个字概述AJAX的作用,那就是:实现局部刷新

在web1.0和web 2.0时代=>整体刷新
那时前端页面的功能和数据绑定大部分都是后台开发者使用后台语言来完成的,浏览器只有一个作用,就是把后台实现好的功能的页面呈现即可,所有操作的都是后台服务器完成,这样若前端页面需要改变,必须后台把最新的内容重新返回,前端页面需要重新刷新

作用:

    AJAX获取数据四部曲:

    //创建ajax对象xhr
    var xhr = new XMLHttpRequest();//ie6及以下不兼容,用new ActiveXObject
    var data = null;

    //打开一个url,配置请求的基本参数信息
    xhr.open('get','temp.xml?name=zf',true);
    //[请求方式]:get post put delete head
    //[请求的url地址]
    //[同步或者异步]:默认是true(异步),false(同步)
    //设置请求的用户名和密码:[userName],[userPass]提供安全权限的验证(一般不用)

    xhr.setRequestHeader('key','value');//

    //监听ajax状态改变,获取服务器返回数据
    xhr.onreadystatechange = function () {
        if(xhr.readyState === 4 && xhr.status === 200){
            //xhr.readyState ajax状态码 0 1 2 3 4
            //xhr.status 服务器返回的http网络状态码200 301 302 304 400 401 404 500 503...
            
            data = JSON.PARSE(xhr.responseText) 服务器端响应主体内容,获取到的是字符串
            //xhr.responseXML 服务器端响应主体内容,获取到的是XML格式数据
           
            //获取响应头的两种方式
            //xhr.getResponseHeader('key')
            //xhr.getAllResponseHeaders()
        }
    };
    xhr.send(null);
    //发送请求,括号内的传递的内容是请求主体

AJAX知识分解

1、创建AJAX对象

var xhr = new XMLHttpRequest();//ie6及以下不兼容,用new ActiveXObject

2、打来一个请求的url地址

例:xhr.open('get','temp.xml?name=zf',true);
xhr.open([method],[request url],[true/false],[username],[userpass]);
//[method]:get post put delete head
//[request url]
//[true/false]:默认是true(异步),false(同步),项目中为防止出现请求阻塞的问题,大多采用异步
//[userName],[userPass]:设置请求的用户名和密码,提供安全权限的验证(一般不用)

注意:无论那种请求方式,都可以向服务器发送和接收数据,且从本质意义上来讲他们没有任何区别,只是约定俗成的规则,在不同的情况下使用不同的请求方式

get与post的区别:
核心:get通过问号传参的方式给服务器传递内容,而post通过请求主体给服务器传递内容

xhr.open('get','temp.json?name=wang&age=18')//get方式,问号传参传递
xhr.send('{"name":"wang","age":18}'//post方式,请求主体传递

一般get、delete、head等用问号传参的方式给服务器传递内容,post、put等用请求主体的方式给服务器传递内容
请求方式get系列与post系列之间存在的问题:

xhr.open('get','temp.json?_=' + Math.random())
//这里的问号传参中属性名使用的是下划线_,是因为除了传随机数外,我们可能还会传递其他的信息,这样的话随机数的属性名可能会与其他信息的属性名冲突,所以用_做属性名防止冲突

面试题:在你以前的项目中服务器返回的数据一般是什么格式的

  1. 返回的是字符串格式的
  1. 返回的是XML格式的

3、监听状态改变

面试题:你之前的项目中做过倒计时之类的东西吗?从服务器读取时间你是怎么解决时间差的?
由于服务器返回给客户端的时间信息在响应头信息的Date属性中,所以当我们只需要获取服务器的时间信息时,可以用head的传递方式,且在监听xhr状态时,在readyState状态码为2的时候,就已经获取到响应头信息了,此时就可以获取到服务器的Date数据了,就没必要在状态码为4的时候去获取信息了,这样请求的效率更高,代码如下:

xhr.onreadystatechange = function () {
    if (xhr.status !== 200) return;//if后没有大括号则只会对if判断后的第一条语句生效;
    if (xhr.readyState === 2) {//->我们只需要响应头信息返回就可以获取到服务器的时间,如果等到4的时候,虽然也可以获取到,但是间隔的时间更长了,导致时间差也会变大(真实时间和服务器获取的时间差值)
        var time = xhr.getResponseHeader('Date');//->获取到的时间是格林尼治时间(GMT),我们还需要把这个时间变为北京时间(GMT+0800)
        time = new Date(time);//转换为本地客户端时区的时间
        console.log(time);
    }
};

4、发送ajax请求给服务器

xhr.send(null);
//get系列请求传递一般是null,post系列请求把请求主体放在send参数里

AJAX一次任务的开始和结束标志:

AJAX方法封装(仿JQ,基础版)

jQuery中的ajax方法

下面是jq中的ajax方法调用,jq中的ajax有30多个参数,一下列举了部分常用参数

$.ajax({
            url: 'temp.json',
            method: 'get',//->type:'get' 和这个属性是一样的功能的,定义请求方式
            
            dataType: 'json',//->预设服务器返回的数据内容的格式json(默认)、text、xml...
            
            data: null,//->设置请求主体的内容,如果是get请求,jQ会把这些内容放到请求地址的末尾,通过问号传参的方式传递给服务器,post请求才是放在请求主体中
            
            cache: true,//->是否保留get请求的缓存,true是保留get缓存,设置成为false是清除缓存(在URL末尾加随机数),此参数对于post请求无效
            
            async: true,//->设置同步异步,默认是TRUE代表异步
            
            //timeout:3000,//->设置请求超时的时间,如果超过3000ms,当前请求自动中断(一般不用)
            
            success: function (result) {
                //->当数据请求成功后执行的回调函数,result就是从服务器获取的结果
                console.log(result);
            },
            
            error: function (msg) {
                //->当数据请求失败指定的回调函数,msg就是失败的原因
            }
        });

以下是仿jQ的ajax基础版方法源码(注释版)

(function () {

    //->验证当前的URL中是否包含问号,包含返回&,否则返回?
    function check(url) {
        return url.indexOf('?') > -1 ? '&' : '?';
    }

    //->把对象转换为字符串
    function formatData(obj) {
        var str = '';
        for (var key in obj) {
            if (obj.hasOwnProperty(key)) {
                str += key + '=' + obj[key] + '&';
            }
        }
        str = str.substring(0, str.length - 1);
        return str;
    }

    function ajax(options) {

        //1、设置参数的默认值
        var _default = {//设置参数默认值,default是关键字 所以要加下划线
            url: null,
            method: 'get',
            data: null,
            dataType: 'json',//->text、xml...
            async: true,
            cache: true,
            success: null,
            error: null
        };

        //2、使用传递进来的参数配置值把默认值进行替换
        for (var key in options) {
            if (options.hasOwnProperty(key)) {
                //for in循环可以遍历到__proto__公有属性中自己拓展的方法,所以先判断一下是不是私有属性
                if (key === 'type') {
                    _default['method'] = options['type'];
                    continue;
                }
                _default[key] = options[key];
            }
        }

        //3、发送AJAX请求
        var xhr = new XMLHttpRequest;
        var regGET = /^(get|delete|head)$/i;
        
        //->3.3:处理DATA
        //对象和字符串的区分,如果是对象需要转换为字符串:xxx=xxx&xxx=xxx...
        if (_default.data !== null) {
            if (typeof _default.data === 'object') {
                _default.data = formatData(_default.data);
            }
            //GET和POST的区分,GET是把内容放在问号后面
            if (regGET.test(_default.method)) {
                char = check(_default.url);
                _default.url += char + _default.data;
                _default.data = null;//->在发送的时候GET请求的请求主体是null
            }
        }

        //->3.2:处理CACHE,如果当前的请求是GET系列的,并且CACHE等于FALSE,我们清除缓存
        if (regGET.test(_default.method) && _default.cache === false) {
            var char = check(_default.url);
            _default.url += char + '_=' + Math.random();
        }

        xhr.open(_default.method, _default.url, _default.async);
        xhr.onreadystatechange = function () {
            if (/^(2|3)\d{2}$/.test(xhr.status)) {
                if (xhr.readyState === 4) {
                    
                    //->3.1:我们从服务器端获取的数据一般都是字符串格式的,但是我们传递进来的参数值中的dataType预设了最后数据结果的类型,所以我们还需要自己进行数据的二次加工,把从服务器端获取的字符串转换为预设的结果
                    var result = xhr.responseText; 
                    switch (_default.dataType.toUpperCase()) {
                        case 'JSON':
                            result = 'JSON' in window ? JSON.parse(result) : eval('(' + result + ')');
                            break;
                        case 'XML':
                            result = xhr.responseXML;
                            break;
                    }
                    _default.success && _default.success.call(xhr, result);
                }
                //->问题:JQ中的dataType是否影响了服务器的返回结果? 不影响,服务器端会根据产品需求给我们返回字符串或者XML数据,而JQ会根据我们设置的dataType值,把返回的结果二次解析成需要的类型
                return;
            }
            //->失败:执行ERROR的回调函数,让函数中的THIS指向当前实例XHR,并且把错误信息传递给回调函数
            //typeof _default.error === 'function' ? _default.error.call(xhr, xhr.responseText) : null;
            _default.error && _default.error.call(xhr, xhr.responseText);//->这种写法和上面的相同,都是在判断只有传递了回调函数的情况下才会执行(项目中一般都这么写)
        };
        xhr.send(_default.data);
    }

    window.ajax = ajax;
}())();

以下是仿jQ的ajax基础版方法源码(无注释版)

~function () {
    function check(url) {
        return url.indexOf('?') > -1 ? '&' : '?';
    }

    function formatData(obj) {
        var str = '';
        for (var key in obj) {
            if (obj.hasOwnProperty(key)) {
                str += key + '=' + obj[key] + '&';
            }
        }
        str = str.substring(0, str.length - 1);
        return str;
    }

    function ajax(options) {
        var _default = {
            url: null,
            method: 'get',
            data: null,
            dataType: 'json',
            async: true,
            cache: true,
            success: null,
            error: null
        };
        for (var key in options) {
            if (options.hasOwnProperty(key)) {
                if (key === 'type') {
                    _default['method'] = options['type'];
                    continue;
                }
                _default[key] = options[key];
            }
        }
        var xhr = new XMLHttpRequest;
        var regGET = /^(get|delete|head)$/i;
        if (_default.data !== null) {
            if (typeof _default.data === 'object') {
                _default.data = formatData(_default.data);
            }
            if (regGET.test(_default.method)) {
                char = check(_default.url);
                _default.url += char + _default.data;
                _default.data = null;
            }
        }
        if (regGET.test(_default.method) && _default.cache === false) {
            var char = check(_default.url);
            _default.url += char + '_=' + Math.random();
        }
        xhr.open(_default.method, _default.url, _default.async);
        xhr.onreadystatechange = function () {
            if (/^(2|3)\d{2}$/.test(xhr.status)) {
                if (xhr.readyState === 4) {
                    var result = xhr.responseText;
                    switch (_default.dataType.toUpperCase()) {
                        case 'JSON':
                            result = 'JSON' in window ? JSON.parse(result) : eval('(' + result + ')');
                            break;
                        case 'XML':
                            result = xhr.responseXML;
                            break;
                    }
                    _default.success && _default.success.call(xhr, result);
                }
                return;
            }
            _default.error && _default.error.call(xhr, xhr.responseText);
        };
        xhr.send(_default.data);
    }

    window.ajax = ajax;
}();
上一篇下一篇

猜你喜欢

热点阅读