# 手写ajax

  1. 这个概念其实作为前端开发在熟悉不过了
  2. 写此文只是回顾了解$.ajax的使用等
  3. 本文只是一个mini版本的 基于xhr构造

原生调用方法

我这里截取测试案例某一段具体可以看源码
    const _ajax = $.ajax({
      context: oTest, //改变this指向为otest这个div
      type: 'post',
      // contentType: 'application/json', //发送到服务器的数据类型。
      // beforeSend: function (body) {
      //   console.log('body', body);
      //   return body;
      // },
      // ifModified: true, //设置http请求缓存 则只有当服务器端的内容与上次请求不一样时,才会发出本次请求
      headers: {
        //指定HTTP请求的头信息。
        a: 1
      },
      dataType: 'json', //dataType设置你收到服务器数据的格式。
      url: 'https://www.fastmock.site/mock/3277f26b72e3b8aa6de012d30c06ce3f/api/prodcut#!method=POST&queryParameters=%5B%5D&body=%7B%0A+%22id%22%3A+1%0A%7D&headers=%5B%5D',
      data: {
        id: 1
      },
      success: function (res) {
        console.log($(this).html(res.desc || 'hello'));
        console.log('res', res);
      },
      error: function (e) {
        // 抛错的钩子函数
      }
    });

      _ajax上面还有一些方法诸如abort等
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

手写mini版ajax

/**
 * 封装一个ajax
 *
 *
 */

function stringGetParams(url, params) {
  return Object.keys(params).reduce((prev, nextKey) => {
    const quot = prev.includes('?') ? '&' : '?';
    prev += `${quot}${nextKey}=${params[nextKey]}`;
    return prev;
  }, url);
}

class MyAjax {
  constructor(options) {
    this.options = this.initOption(options);
    this.initRequest();
  }

  static onXHRStateChange(options = this.options) {
    // const that = this;
    // readyState五个状态
    // 0:未初始化(Uninitialized)。尚未调用 open()方法。
    // 1:已打开(Open)。已调用 open()方法,尚未调用 send()方法。
    // 2:已发送(Sent)。已调用 send()方法,尚未收到响应。
    // 3:接收中(Receiving)。已经收到部分响应。
    // 4:完成(Complete)。已经收到所有响应,可以使用了。
    return function () {
      // console.log('MyAjax.xhr--init', MyAjax.xhr);
      if (MyAjax.xhr.readyState === 4) {
        options.complete && options.complete();
        if (MyAjax.xhr.status === 200) {
          // console.log('MyAjax.xhr-success', MyAjax.xhr);
          options.success && options.success(MyAjax.xhr.responseText);
        } else {
          // console.log('MyAjax.xhr-error', MyAjax.xhr);
          options.error &&
            options.error(MyAjax.xhr, MyAjax.xhr.status, MyAjax.xhr.statusText);
        }
      }
    }.bind(this);
  }

  static xhr = new XMLHttpRequest();

  initRequest() {
    const { type, data, url, success, error, complete } = this.options;
    const isGet = type.toLowerCase() === 'get';
    if (isGet) {
      MyAjax.getMethod(url, data, success, error, complete);
    } else {
      MyAjax.postMethod(url, data, success, error, complete);
    }
  }

  static getMethod(url, params, success, error, complete) {
    console.log('this', this);
    const finalUrl = stringGetParams(url, params);
    let combineOptions = {
      url: finalUrl,
      type: 'get',
      success,
      error,
      complete
    };
    this.options = this.options
      ? {
          ...this.options,
          combineOptions
        }
      : combineOptions;
    MyAjax.xhr.open('get', finalUrl);
    MyAjax.xhr.onreadystatechange = this.onXHRStateChange();
    MyAjax.xhr.send();
    return MyAjax.xhr;
  }

  static postMethod(url, params, success, error, complete) {
    // console.log('params', params);
    const finalData = JSON.stringify(params || {});
    let combineOptions = {
      url,
      type: 'post',
      data: finalData,
      success,
      error,
      complete
    };
    this.options = this.options
      ? {
          ...this.options,
          combineOptions
        }
      : combineOptions;

    // console.log('finalData', finalData);
    MyAjax.xhr.open('post', url);
    MyAjax.xhr.setRequestHeader('Content-type', 'application/json'); //默认配置
    MyAjax.xhr.onreadystatechange = this.onXHRStateChange();
    MyAjax.xhr.send(finalData);
    return MyAjax.xhr;
  }

  initOption(options) {
    options.type = options.type.toUpperCase() || 'GET';
    options.async ||= true;
    options.data ||= {};
    options.dataType ||= 'JSON';
    options.timeout ||= 10000;
    options.complete ||= function () {};
    options.success ||= function () {};
    options.error ||= function () {};
    return options;
  }

  abort() {
    if (MyAjax.xhr) {
      MyAjax.xhr.abort();
      MyAjax.xhr = null;
    }
  }
}


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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

这里我截取一段代码使用

image.png

附注:源码 (opens new window)

最后更新时间: 5/16/2023, 12:44:06 AM