AJAX常见的几种封装方法实例详解

Written by

in

文章目录
  • AJAX (Asynchronous JavaScript and XML) 封装是为了简化重复的异步请求代码,提高开发效率和代码复用性。下面我将介绍几种常见的 AJAX 封装方式。
  • XMLHttpRequest。其主要特点如下: 实现动态不刷新,通过异步⽅式,提升⽤户体验,优化了浏览器和服务器之间的传输。 把⼀部分原本由服务器负担的⼯作转移到客户端,利⽤客户端闲置的资源进⾏处理,减轻服务器和带宽的负担,节约空间和成本。 ⽆刷新更新⻚⾯,⽤户不⽤再像以前⼀样在服务器处理数据时,只能在死板的⽩屏前焦急的等待。AJAX使⽤XMLHttpRequest对象发送请求并得到服务器响应,在不需要重新载⼊整个⻚⾯的情况下,就可以通过DOM及时将更新的内容显示在⻚⾯上。 /** * 基于原生XHR的AJAX封装 * @param {Object} options 配置对象 * @param {string} options.url 请求地址 * @param {string} [options.method=’GET’] 请求方法 * @param {Object} [options.data=null] 请求数据 * @param {Object} [options.headers={}] 请求头 * @param {function} [options.success] 成功回调 * @param {function} [options.error] 失败回调 */ function ajax(options) { const xhr = new XMLHttpRequest(); const method = options.method || ‘GET’; let url = options.url; let data = options.data || null; // 处理GET请求的查询参数 if (method === ‘GET’ && data) { const params = new URLSearchParams(); for (const key in data) { params.append(key, data[key]); } url += ‘?’ + params.toString(); data = null; } xhr.open(method, url, true); // 设置请求头 if (options.headers) { for (const key in options.headers) { xhr.setRequestHeader(key, options.headers[key]); } } xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300) { let response = xhr.responseText; try { response = JSON.parse(response); } catch (e) {} options.success && options.success(response); } else { options.error && options.error(xhr.status, xhr.statusText); } } }; xhr.onerror = function() { options.error && options.error(-1, ‘Network Error’); }; // 发送请求 if (data && typeof data === ‘object’) { xhr.setRequestHeader(‘Content-Type’, ‘application/json’); xhr.send(JSON.stringify(data)); } else { xhr.send(data); } } // 使用示例 ajax({ url: ‘/api/user’, method: ‘POST’, data: { name: ‘John’, age: 30 }, headers: { ‘Authorization’: ‘Bearer token123’ }, success: function(response) { console.log(‘Success:’, response); }, error: function(status, statusText) { console.error(‘Error:’, status, statusText); } });
  • /** * 基于Fetch API的AJAX封装 * @param {string} url 请求地址 * @param {Object} [options={}] 请求配置 * @returns {Promise} 返回Promise对象 */ function fetchAjax(url, options = {}) { const defaultOptions = { method: ‘GET’, headers: { ‘Content-Type’: ‘application/json’ }, credentials: ‘same-origin’, // 携带cookie …options }; // 处理GET请求的查询参数 if (defaultOptions.method === ‘GET’ && defaultOptions.body) { const params = new URLSearchParams(); for (const key in defaultOptions.body) { params.append(key, defaultOptions.body[key]); } url += ‘?’ + params.toString(); delete defaultOptions.body; } // 处理非GET请求的body数据 if (defaultOptions.body && typeof defaultOptions.body === ‘object’) { defaultOptions.body = JSON.stringify(defaultOptions.body); } return fetch(url, defaultOptions) .then(async response => { const data = await response.json().catch(() => ({})); if (!response.ok) { const error = new Error(response.statusText); error.response = response; error.data = data; throw error; } return data; }); } // 使用示例 fetchAjax(‘/api/user’, { method: ‘POST’, body: { name: ‘John’, age: 30 }, headers: { ‘Authorization’: ‘Bearer token123’ } }) .then(data => console.log(‘Success:’, data)) .catch(err => console.error(‘Error:’, err));
  • class Ajax { constructor(baseURL = ”, timeout = 10000) { this.baseURL = baseURL; this.timeout = timeout; this.interceptors = { request: [], response: [] }; } request(config) { // 处理请求拦截器 let chain = [this._dispatchRequest, undefined]; this.interceptors.request.forEach(interceptor => { chain.unshift(interceptor.fulfilled, interceptor.rejected); }); this.interceptors.response.forEach(interceptor => { chain.push(interceptor.fulfilled, interceptor.rejected); }); let promise = Promise.resolve(config); while (chain.length) { promise = promise.then(chain.shift(), chain.shift()); } return promise; } _dispatchRequest(config) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); let url = config.baseURL ? config.baseURL + config.url : config.url; let data = config.data; // 处理GET请求参数 if (config.method === ‘GET’ && data) { const params = new URLSearchParams(); for (const key in data) { params.append(key, data[key]); } url += ‘?’ + params.toString(); data = null; } xhr.timeout = config.timeout || 10000; xhr.open(config.method, url, true); // 设置请求头 if (config.headers) { for (const key in config.headers) { xhr.setRequestHeader(key, config.headers[key]); } } xhr.onload = function() { if (xhr.status >= 200 && xhr.status < 300) { let response = xhr.responseText; try { response = JSON.parse(response); } catch (e) {} resolve({ data: response, status: xhr.status, statusText: xhr.statusText, headers: xhr.getAllResponseHeaders() }); } else { reject(new Error(`Request failed with status code ${xhr.status}`)); } }; xhr.onerror = function() { reject(new Error(‘Network Error’)); }; xhr.ontimeout = function() { reject(new Error(‘Timeout’)); }; // 发送请求 if (data && typeof data === ‘object’) { xhr.setRequestHeader(‘Content-Type’, ‘application/json’); xhr.send(JSON.stringify(data)); } else { xhr.send(data); } }); } get(url, config = {}) { return this.request({ …config, method: ‘GET’, url }); } post(url, data, config = {}) { return this.request({ …config, method: ‘POST’, url, data }); } // 添加拦截器 useRequestInterceptor(fulfilled, rejected) { this.interceptors.request.push({ fulfilled, rejected }); return this.interceptors.request.length – 1; } useResponseInterceptor(fulfilled, rejected) { this.interceptors.response.push({ fulfilled, rejected }); return this.interceptors.response.length – 1; } // 移除拦截器 ejectRequestInterceptor(id) { if (this.interceptors.request[id]) { this.interceptors.request.splice(id, 1); } } ejectResponseInterceptor(id) { if (this.interceptors.response[id]) { this.interceptors.response.splice(id, 1); } } } // 使用示例 const api = new Ajax(‘https://api.example.com’); // 添加请求拦截器 api.useRequestInterceptor(config => { config.headers = config.headers || {}; config.headers[‘Authorization’] = ‘Bearer token123’; return config; }); // 添加响应拦截器 api.useResponseInterceptor(response => { console.log(‘Response:’, response); return response.data; }, error => { console.error(‘Error:’, error); return Promise.reject(error); }); // 发起请求 api.get(‘/user/123’) .then(data => console.log(‘User data:’, data)) .catch(err => console.error(‘Error:’, err)); api.post(‘/user’, { name: ‘John’, age: 30 }) .then(data => console.log(‘Created user:’, data)) .catch(err => console.error(‘Error:’, err));
  • 统一接口:提供一致的调用方式,如get(), post()等方法 参数处理: GET请求自动拼接查询参数 POST请求自动处理Content-Type 拦截器机制:支持请求/响应拦截 错误处理:统一错误处理逻辑 Promise支持:返回Promise便于链式调用 超时处理:设置合理的请求超时时间 扩展性:支持自定义配置和拦截器
  • 目录
    • 前言
    • 方法1. 基于原生 XMLHttpRequest 的封装
    • 方法2. 基于 Fetch API 的封装
    • 方法 3. 基于 Axios 风格的封装
    • 4. 封装要点总结
    • 5. 实际项目中的增强功能
      • 1.自动重试机制:
      • 2.请求取消功能:
      • 3.请求缓存:

    AJAX (Asynchronous JavaScript and XML) 封装是为了简化重复的异步请求代码,提高开发效率和代码复用性。下面我将介绍几种常见的 AJAX 封装方式。

    XMLHttpRequest。其主要特点如下:

    1. 实现动态不刷新,通过异步⽅式,提升⽤户体验,优化了浏览器和服务器之间的传输。
    2. 把⼀部分原本由服务器负担的⼯作转移到客户端,利⽤客户端闲置的资源进⾏处理,减轻服务器和带宽的负担,节约空间和成本。
    3. ⽆刷新更新⻚⾯,⽤户不⽤再像以前⼀样在服务器处理数据时,只能在死板的⽩屏前焦急的等待。AJAX使⽤XMLHttpRequest对象发送请求并得到服务器响应,在不需要重新载⼊整个⻚⾯的情况下,就可以通过DOM及时将更新的内容显示在⻚⾯上。
    /**
     * 基于原生XHR的AJAX封装
     * @param {Object} options 配置对象
     * @param {string} options.url 请求地址
     * @param {string} [options.method='GET'] 请求方法
     * @param {Object} [options.data=null] 请求数据
     * @param {Object} [options.headers={}] 请求头
     * @param {function} [options.success] 成功回调
     * @param {function} [options.error] 失败回调
     */
    function ajax(options) {
      const xhr = new XMLHttpRequest();
      const method = options.method || 'GET';
      let url = options.url;
      let data = options.data || null;
    
      // 处理GET请求的查询参数
      if (method === 'GET' && data) {
        const params = new URLSearchParams();
        for (const key in data) {
          params.append(key, data[key]);
        }
        url += '?' + params.toString();
        data = null;
      }
    
      xhr.open(method, url, true);
    
      // 设置请求头
      if (options.headers) {
        for (const key in options.headers) {
          xhr.setRequestHeader(key, options.headers[key]);
        }
      }
    
      xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
          if (xhr.status >= 200 && xhr.status < 300) {
            let response = xhr.responseText;
            try {
              response = JSON.parse(response);
            } catch (e) {}
            options.success && options.success(response);
          } else {
            options.error && options.error(xhr.status, xhr.statusText);
          }
        }
      };
    
      xhr.onerror = function() {
        options.error && options.error(-1, 'Network Error');
      };
    
      // 发送请求
      if (data && typeof data === 'object') {
        xhr.setRequestHeader('Content-Type', 'application/json');
        xhr.send(JSON.stringify(data));
      } else {
        xhr.send(data);
      }
    }
    
    // 使用示例
    ajax({
      url: '/api/user',
      method: 'POST',
      data: { name: 'John', age: 30 },
      headers: {
        'Authorization': 'Bearer token123'
      },
      success: function(response) {
        console.log('Success:', response);
      },
      error: function(status, statusText) {
        console.error('Error:', status, statusText);
      }
    });
    

    /**
     * 基于Fetch API的AJAX封装
     * @param {string} url 请求地址
     * @param {Object} [options={}] 请求配置
     * @returns {Promise} 返回Promise对象
     */
    function fetchAjax(url, options = {}) {
      const defaultOptions = {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json'
        },
        credentials: 'same-origin', // 携带cookie
        ...options
      };
    
      // 处理GET请求的查询参数
      if (defaultOptions.method === 'GET' && defaultOptions.body) {
        const params = new URLSearchParams();
        for (const key in defaultOptions.body) {
          params.append(key, defaultOptions.body[key]);
        }
        url += '?' + params.toString();
        delete defaultOptions.body;
      }
    
      // 处理非GET请求的body数据
      if (defaultOptions.body && typeof defaultOptions.body === 'object') {
        defaultOptions.body = JSON.stringify(defaultOptions.body);
      }
    
      return fetch(url, defaultOptions)
        .then(async response => {
          const data = await response.json().catch(() => ({}));
          if (!response.ok) {
            const error = new Error(response.statusText);
            error.response = response;
            error.data = data;
            throw error;
          }
          return data;
        });
    }
    
    // 使用示例
    fetchAjax('/api/user', {
      method: 'POST',
      body: { name: 'John', age: 30 },
      headers: {
        'Authorization': 'Bearer token123'
      }
    })
    .then(data => console.log('Success:', data))
    .catch(err => console.error('Error:', err));
    

    class Ajax {
      constructor(baseURL = '', timeout = 10000) {
        this.baseURL = baseURL;
        this.timeout = timeout;
        this.interceptors = {
          request: [],
          response: []
        };
      }
    
      request(config) {
        // 处理请求拦截器
        let chain = [this._dispatchRequest, undefined];
        this.interceptors.request.forEach(interceptor => {
          chain.unshift(interceptor.fulfilled, interceptor.rejected);
        });
        this.interceptors.response.forEach(interceptor => {
          chain.push(interceptor.fulfilled, interceptor.rejected);
        });
    
        let promise = Promise.resolve(config);
        while (chain.length) {
          promise = promise.then(chain.shift(), chain.shift());
        }
        return promise;
      }
    
      _dispatchRequest(config) {
        return new Promise((resolve, reject) => {
          const xhr = new XMLHttpRequest();
          let url = config.baseURL ? config.baseURL + config.url : config.url;
          let data = config.data;
    
          // 处理GET请求参数
          if (config.method === 'GET' && data) {
            const params = new URLSearchParams();
            for (const key in data) {
              params.append(key, data[key]);
            }
            url += '?' + params.toString();
            data = null;
          }
    
          xhr.timeout = config.timeout || 10000;
          xhr.open(config.method, url, true);
    
          // 设置请求头
          if (config.headers) {
            for (const key in config.headers) {
              xhr.setRequestHeader(key, config.headers[key]);
            }
          }
    
          xhr.onload = function() {
            if (xhr.status >= 200 && xhr.status < 300) {
              let response = xhr.responseText;
              try {
                response = JSON.parse(response);
              } catch (e) {}
              resolve({
                data: response,
                status: xhr.status,
                statusText: xhr.statusText,
                headers: xhr.getAllResponseHeaders()
              });
            } else {
              reject(new Error(`Request failed with status code ${xhr.status}`));
            }
          };
    
          xhr.onerror = function() {
            reject(new Error('Network Error'));
          };
    
          xhr.ontimeout = function() {
            reject(new Error('Timeout'));
          };
    
          // 发送请求
          if (data && typeof data === 'object') {
            xhr.setRequestHeader('Content-Type', 'application/json');
            xhr.send(JSON.stringify(data));
          } else {
            xhr.send(data);
          }
        });
      }
    
      get(url, config = {}) {
        return this.request({
          ...config,
          method: 'GET',
          url
        });
      }
    
      post(url, data, config = {}) {
        return this.request({
          ...config,
          method: 'POST',
          url,
          data
        });
      }
    
      // 添加拦截器
      useRequestInterceptor(fulfilled, rejected) {
        this.interceptors.request.push({ fulfilled, rejected });
        return this.interceptors.request.length - 1;
      }
    
      useResponseInterceptor(fulfilled, rejected) {
        this.interceptors.response.push({ fulfilled, rejected });
        return this.interceptors.response.length - 1;
      }
    
      // 移除拦截器
      ejectRequestInterceptor(id) {
        if (this.interceptors.request[id]) {
          this.interceptors.request.splice(id, 1);
        }
      }
    
      ejectResponseInterceptor(id) {
        if (this.interceptors.response[id]) {
          this.interceptors.response.splice(id, 1);
        }
      }
    }
    
    // 使用示例
    const api = new Ajax('https://api.example.com');
    
    // 添加请求拦截器
    api.useRequestInterceptor(config => {
      config.headers = config.headers || {};
      config.headers['Authorization'] = 'Bearer token123';
      return config;
    });
    
    // 添加响应拦截器
    api.useResponseInterceptor(response => {
      console.log('Response:', response);
      return response.data;
    }, error => {
      console.error('Error:', error);
      return Promise.reject(error);
    });
    
    // 发起请求
    api.get('/user/123')
      .then(data => console.log('User data:', data))
      .catch(err => console.error('Error:', err));
    
    api.post('/user', { name: 'John', age: 30 })
      .then(data => console.log('Created user:', data))
      .catch(err => console.error('Error:', err));
    

    统一接口:提供一致的调用方式,如get(), post()等方法

    参数处理:

    GET请求自动拼接查询参数

    POST请求自动处理Content-Type

    拦截器机制:支持请求/响应拦截

    错误处理:统一错误处理逻辑

    Promise支持:返回Promise便于链式调用

    超时处理:设置合理的请求超时时间

    扩展性:支持自定义配置和拦截器

    function withRetry(fn, retries = 3, delay = 1000) {
      return function(...args) {
        return new Promise((resolve, reject) => {
          function attempt(retryCount) {
            fn(...args)
              .then(resolve)
              .catch(err => {
                if (retryCount < retries) {
                  setTimeout(() => attempt(retryCount + 1), delay);
                } else {
                  reject(err);
                }
              });
          }
          attempt(0);
        });
      };
    }
    
    // 使用示例
    const ajaxWithRetry = withRetry(ajax, 3, 1000);
    

    function createCancelToken() {
      let cancel;
      const token = new Promise((resolve, reject) => {
        cancel = reject;
      });
      return { token, cancel };
    }
    
    // 在请求中检查取消token
    function ajaxWithCancel(options) {
      const { token, cancel } = createCancelToken();
      const xhr = new XMLHttpRequest();
      
      const promise = new Promise((resolve, reject) => {
        // ...正常请求逻辑
        
        // 检查取消
        token.catch(err => {
          xhr.abort();
          reject(err);
        });
      });
      
      return { promise, cancel };
    }
    

    const cache = new Map();
    
    function cachedAjax(options) {
      const cacheKey = JSON.stringify(options);
      
      if (cache.has(cacheKey)) {
        return Promise.resolve(cache.get(cacheKey));
      }
      
      return ajax(options).then(response => {
        cache.set(cacheKey, response);
        return response;
      });
    }
    

    根据项目需求选择合适的封装方式,小型项目可使用简单封装,大型项目建议使用成熟的库如Axios。

    到此这篇关于AJAX常见的几种封装方法的文章就介绍到这了,更多相关AJAX封装方法内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

    您可能感兴趣的文章:

    • 基于jQuery的ajax方法封装
    • 封装了jQuery的Ajax请求全局配置
    • 原生Javascript封装的一个AJAX函数分享
    • 自己动手封装的 ajax
    • 纯js封装的ajax功能函数与用法示例
    • 原生js封装的ajax方法示例
    • 一个封装的Ajax类
    • ajax的工作原理以及异步请求的封装介绍

    站内搜索