前端系统课程 - 35. 自己实现 AJAX

AJAX 设置请求报文

  • AJAX 对象 open() 方法的第一个参数对应请求报文第一部分中的请求方式,第二个参数则包含了第一部分中的路径和协议,同时包含第二部分中的 Host 内容。

  • 使用 setRequestHeader() 方法可以设置请求报文中的第二部分中的内容,这个方法需要在 open()send() 之间使用;接收两个字符串类型的参数,分别是第二部分内容的 key 和 value;例如:setRequestHeader('Content-Type', 'x-www-form-urlencoded')。第二部分的有些内容是禁止修改的,例如浏览器(用户)信息。

  • 请求报文的第四部分也就是请求体,则需要使用 send() 方法设置,它接收一个字符串类型的参数,对应的就是请求报文体的内容;要注意请求报文体使用 GET 方法发送时,是不会展示的。

AJAX 获取响应报文

  • 响应报文由服务端设置并发送,而用 AJAX 可以获取响应报文;获取第一部分中的状态码就是响应成功后 status 属性的值,状态信息则可以通过 statusText 属性来获取。

  • 使用 AJAX 对象的 getAllResponseHeaders() 方法可以获取响应报文第二部分整个内容,返回值是字符串;如果要获取某一个内容的值,可以使用 getResponseHeader() 方法,将要获取内容的 key 传入即可。

  • 响应报文的第四报文就是我们最需要的数据,通过 responseText 属性获取即可。

封装 AJAX

  • 如果参数较多,为了使参数更加直观,函数接收参数可以用对象的形式,每个参数就是这个对象的一个属性,属性名可以很好的将参数的功能标示并区分开,这种方式叫做“参数命名”。

  • 通过判断函数参数列表的长度或者每个参数的类型,可以让函数接收不同个数或者不同类型的参数,进而做出不同的处理,这就是 JavaScript 中的函数重载。

  • 简易封装代码示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    function ajax(options) {
    let ajax,
    method = options.method || 'GET',
    url = options.url,
    async = options.async || true,
    headers = options.headers,
    body = options.body,
    success = options.success,
    fail = options.fail;

    if (window.XMLHttpRequest) {
    ajax = new XMLHttpRequest();
    } else {
    ajax = new ActiveXObject('Microsoft.XMLHTTP');
    }

    ajax.open(method, url, async);

    for (let key in headers) {
    if (headers.hasOwnProperty(key)) {
    ajax.setRequestHeader(key, headers[key]);
    }
    }

    ajax.addEventListener('readystatechange', () => {
    if (ajax.readyState === 4) {
    if (ajax.status === 200) {
    console.log('Success!');
    success.call(undefined, responseText);
    } else {
    console.log('Fail……');
    fail && fail.call(undefined, ajax);
    }
    }
    });

    ajax.send(body);
    }

ES6 中的解构赋值

前面的封装函数中的参数,除了 AJAX 对象,剩下的都是来自 options 这个对象参数;在 ES6 中,如果参数和对象中属性顺序相同,可以直接写作 {method, url, async, headers, body, success, fail} = options,或者直接将代码块放入参数即可,这是解构赋值的一种应用;还有一个比较常见的应用,例如两个变量交换:

1
2
3
4
5
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a); // 2
console.log(b); // 1

这种语法在一些语言中很早就实现了。

ES6 中的 Promise

  • Promise() 是一个全局方法,它可以看做是一种确定函数形式的规范。

  • 在 jQuery 的 AJAX 方法调用后,再使用 then() 方法就可以运行成功或失败的回调函数,成功是第一个参数,失败是第二个参数。

  • 使用 then() 方法运行的回调函数还可以将操作结果返回,以供下一个 then() 方法使用,这样就可以多结果进行多次处理了,例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $.ajax(
    ...somcode
    ).then(
    (responseText) => {
    console.log('第一次处理的' + responseText);
    return responseText;
    },
    (error) => {
    console.log(error);
    return error;
    }
    ).then(
    responseText => console.log('上次处理后的' + responseText),
    error => console.log(error)
    );
  • then() 方法是 Promise 实例的方法,创建 Promise 实例可以在 AJAX 函数内,直接返回一个实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function ajax(options) {
    return new Promise((resolve, reject) => {
    let ajax
    ...
    if (ajax.readyState === 4) {
    if (ajax.status === 200) {
    resolve.call(undefined, responseText); // 成功则调用resolve
    } else {
    reject.call(undefined, ajax); // 失败则调用reject
    }
    }
    ...
    });
    }