header-bg.jpg
使用 Promise 封装 XMLHttpRequest 以及 fetch 实现 AJAX
发表于 2018-11-30 00:12
|
分类于 JavaScript
|
评论次数 0
|
阅读次数 3468

10831543506011.gif

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

$.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 有很多缺点(比如不支持监听进度…)

封装 AJAX

拿 XHR 和 fetch 分别封装一个 AJAX,用法如下:

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: '服务器繁忙, 请稍后再试'});
            }
        })
    }
}

Vue 项目中使用:

// main.js引入
import Api from './api'
Vue.prototype.api = Api;

// Promise
this.get('https://baidu.com/api/').then(e => console.log(e));

// Async/Await
let res = await this.get('https://baidu.com/api/');
console.log(res);

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