首页
学习
活动
专区
圈层
工具
发布

使用ES6类封装AJAX

ES6类封装AJAX详解

基础概念

AJAX (Asynchronous JavaScript and XML) 是一种在不重新加载整个页面的情况下与服务器交换数据并更新部分网页的技术。使用ES6类封装AJAX可以创建更结构化、可重用性更高的代码。

优势

  1. 代码复用性:封装后可以在多个地方重复使用
  2. 可维护性:集中管理所有AJAX相关逻辑
  3. 可扩展性:易于添加新功能或修改现有功能
  4. 一致性:统一处理错误和响应
  5. Promise支持:天然支持异步操作

基本实现

下面是一个基本的ES6类封装AJAX的示例:

代码语言:txt
复制
class AjaxRequest {
  constructor() {
    this.xhr = new XMLHttpRequest();
  }

  get(url, params = {}) {
    return new Promise((resolve, reject) => {
      const queryString = Object.entries(params)
        .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
        .join('&');
      
      const requestUrl = queryString ? `${url}?${queryString}` : url;
      
      this.xhr.open('GET', requestUrl);
      this.xhr.onload = () => {
        if (this.xhr.status >= 200 && this.xhr.status < 300) {
          resolve(JSON.parse(this.xhr.response));
        } else {
          reject({
            status: this.xhr.status,
            statusText: this.xhr.statusText
          });
        }
      };
      this.xhr.onerror = () => {
        reject({
          status: this.xhr.status,
          statusText: this.xhr.statusText
        });
      };
      this.xhr.send();
    });
  }

  post(url, data) {
    return new Promise((resolve, reject) => {
      this.xhr.open('POST', url);
      this.xhr.setRequestHeader('Content-Type', 'application/json');
      this.xhr.onload = () => {
        if (this.xhr.status >= 200 && this.xhr.status < 300) {
          resolve(JSON.parse(this.xhr.response));
        } else {
          reject({
            status: this.xhr.status,
            statusText: this.xhr.statusText
          });
        }
      };
      this.xhr.onerror = () => {
        reject({
          status: this.xhr.status,
          statusText: this.xhr.statusText
        });
      };
      this.xhr.send(JSON.stringify(data));
    });
  }

  // 可以继续添加put, delete等方法
}

高级封装(带拦截器)

代码语言:txt
复制
class AdvancedAjax {
  constructor() {
    this.xhr = new XMLHttpRequest();
    this.interceptors = {
      request: [],
      response: []
    };
  }

  useRequestInterceptor(interceptor) {
    this.interceptors.request.push(interceptor);
  }

  useResponseInterceptor(interceptor) {
    this.interceptors.response.push(interceptor);
  }

  async request(config) {
    // 请求拦截
    let currentConfig = config;
    for (const interceptor of this.interceptors.request) {
      currentConfig = await interceptor(currentConfig);
    }

    return new Promise((resolve, reject) => {
      this.xhr.open(currentConfig.method, currentConfig.url);
      
      // 设置请求头
      if (currentConfig.headers) {
        Object.entries(currentConfig.headers).forEach(([key, value]) => {
          this.xhr.setRequestHeader(key, value);
        });
      }

      this.xhr.onload = async () => {
        let response = {
          data: this.xhr.response,
          status: this.xhr.status,
          statusText: this.xhr.statusText,
          headers: this.xhr.getAllResponseHeaders(),
          config: currentConfig
        };

        try {
          response.data = JSON.parse(this.xhr.response);
        } catch (e) {
          // 非JSON响应保持原样
        }

        // 响应拦截
        for (const interceptor of this.interceptors.response) {
          response = await interceptor(response);
        }

        if (this.xhr.status >= 200 && this.xhr.status < 300) {
          resolve(response);
        } else {
          reject(response);
        }
      };

      this.xhr.onerror = () => {
        reject({
          status: this.xhr.status,
          statusText: this.xhr.statusText,
          config: currentConfig
        });
      };

      this.xhr.send(currentConfig.data ? JSON.stringify(currentConfig.data) : null);
    });
  }

  get(url, config = {}) {
    return this.request({
      method: 'GET',
      url,
      ...config
    });
  }

  post(url, data, config = {}) {
    return this.request({
      method: 'POST',
      url,
      data,
      ...config
    });
  }

  // 其他HTTP方法...
}

使用示例

代码语言:txt
复制
// 基本使用
const ajax = new AjaxRequest();
ajax.get('https://api.example.com/data', { page: 1, limit: 10 })
  .then(data => console.log(data))
  .catch(error => console.error(error));

ajax.post('https://api.example.com/data', { name: 'John', age: 30 })
  .then(data => console.log(data))
  .catch(error => console.error(error));

// 高级使用
const advancedAjax = new AdvancedAjax();

// 添加请求拦截器
advancedAjax.useRequestInterceptor(config => {
  console.log('Request interceptor:', config);
  // 可以在这里添加认证token等
  config.headers = config.headers || {};
  config.headers['Authorization'] = 'Bearer token123';
  return config;
});

// 添加响应拦截器
advancedAjax.useResponseInterceptor(response => {
  console.log('Response interceptor:', response);
  // 可以在这里统一处理错误
  if (response.status === 401) {
    // 处理未授权
  }
  return response;
});

advancedAjax.get('https://api.example.com/data')
  .then(response => console.log(response.data))
  .catch(error => console.error(error));

常见问题及解决方案

  1. 跨域问题
    • 原因:浏览器的同源策略限制
    • 解决方案:
      • 服务器设置CORS头
      • 开发时使用代理
      • JSONP(仅限GET请求)
  • 请求超时
    • 解决方案:在类中添加timeout处理
    • 解决方案:在类中添加timeout处理
  • 重复请求取消
    • 解决方案:添加abort方法
    • 解决方案:添加abort方法
  • 错误处理不统一
    • 解决方案:在类中统一处理错误,如添加错误码映射
  • 请求进度
    • 解决方案:添加进度事件处理
    • 解决方案:添加进度事件处理

应用场景

  1. 单页应用(SPA)数据加载
  2. 表单提交
  3. 实时数据更新
  4. 文件上传/下载
  5. 与RESTful API交互
  6. 前后端分离架构中的通信

通过ES6类封装AJAX,可以创建更健壮、可维护的前端数据交互层,提高开发效率和代码质量。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

领券