使用Promise封装XMLHttpRequest以及fetch实现AJAX

远古时代的前端程序猿都是使用JQ的ajax来请求服务器的:

1
2
3
4
5
6
7
8
$.ajax({
   type: "POST",
   url: "some.php",
   data: "name=John&location=Boston",
   success: function(msg){
     console.log( msg );
   }
});
JQ的AJAX底层是使用了XMLHttpRequest对象, 对比现代浏览器所支持的Fetch API, 很多人都觉得XHR对象真是太麻烦了, 但实际上我使用fetch的时候发现fetch并不是那么简单好用, 相反反而觉得XHR对象竟然还好用一些, 因为fetch有很多缺点(比如不支持监听进度...)

直接拿XHR和fetch封装一个AJAX:

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
export default {
    //GET请求
    get(url, data = null) {
        // return this.ajax('GET', url, null);
        return this.fetch('GET', url, data);
    },
 
    //POST请求
    post(url, data = null) {
        // return this.ajax('POST', url, data);
        return this.fetch('POST', url, data);
    },
 
    //PUT请求
    put(url, data = null) {
        // return this.ajax('PUT', url, data);
        return this.fetch('PUT', url, data);
    },
 
    //Delete请求
    del(url, data = null) {
        // return this.ajax('DELETE', url, data);
        return this.fetch('DELETE', url, data);
    },
 
    ajax(method, url, data) {
        return new Promise((resolve, reject) => {
 
            let xhr = new XMLHttpRequest, params = [];
            xhr.responseType = 'json';// 指定返回类型
 
            xhr.onload = () => {
                switch (xhr.status) {
                    case 200: resolve(xhr.response);break;
                    case 204: resolve();break;
                    case 401:// 401登录失败处理
                        //do something
                        reject();
                        break;
                    default: reject({status: xhr.status, res: xhr.response});
                }
            };
             
            if (data) {// 将参数编码成表单的键值对形式
                for (let k in data) params.push(`${encodeURIComponent(k)}=${encodeURIComponent(data[k])}`);
                data = params.join('&');
            }
            xhr.open(method, url, true);
            xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded;charset=utf-8');// 设置content-type
            xhr.withCredentials = true;// 支持跨域发送cookies
            xhr.send(data);
        });
    },
 
    fetch(method, url, data) {
 
        let params = [], init = {
            method,
            mode: 'cors',
            headers: {'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'},
            credentials: 'include',// 支持跨域发送cookies
        };
         
        if (data) {// 将参数编码成表单的键值对形式
            for (let k in data) params.push(`${encodeURIComponent(k)}=${encodeURIComponent(data[k])}`);
 
            if (method === 'GET') {
                url += '?' + params.join('&');
            } else {
                init.body = params.join('&');
            }
        }
 
        return fetch(url, init).then(e => {
            switch (e.status) {
                case 200: return e.json();
                case 204: break;
                case 401:// 401登录失败统一处理
                    //do something
                    return Promise.reject();
                case 403: return e.json().then(e => Promise.reject(e));// 服务端主动抛出错误
                default: return Promise.reject({status_code: 500, message: '服务器繁忙, 请稍后再试'});
            }
        })
    }
}

发布评论
还没有评论,快来抢沙发吧!