最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

AJAX常見(jiàn)的幾種封裝方法實(shí)例詳解

 更新時(shí)間:2025年07月08日 11:19:11   作者:源碼方舟  
封裝Ajax是開(kāi)發(fā)中常見(jiàn)的需求,它能讓我們的代碼更加簡(jiǎn)潔和易于維護(hù),這篇文章主要介紹了AJAX常見(jiàn)的幾種封裝方法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

AJAX (Asynchronous JavaScript and XML) 封裝是為了簡(jiǎn)化重復(fù)的異步請(qǐng)求代碼,提高開(kāi)發(fā)效率和代碼復(fù)用性。下面我將介紹幾種常見(jiàn)的 AJAX 封裝方式。

方法1. 基于原生 XMLHttpRequest 的封裝

XMLHttpRequest。其主要特點(diǎn)如下:

  1. 實(shí)現(xiàn)動(dòng)態(tài)不刷新,通過(guò)異步?式,提升?戶體驗(yàn),優(yōu)化了瀏覽器和服務(wù)器之間的傳輸。
  2. 把?部分原本由服務(wù)器負(fù)擔(dān)的?作轉(zhuǎn)移到客戶端,利?客戶端閑置的資源進(jìn)?處理,減輕服務(wù)器和帶寬的負(fù)擔(dān),節(jié)約空間和成本。
  3. ?刷新更新??,?戶不?再像以前?樣在服務(wù)器處理數(shù)據(jù)時(shí),只能在死板的?屏前焦急的等待。AJAX使?XMLHttpRequest對(duì)象發(fā)送請(qǐng)求并得到服務(wù)器響應(yīng),在不需要重新載?整個(gè)??的情況下,就可以通過(guò)DOM及時(shí)將更新的內(nèi)容顯示在??上。
/**
 * 基于原生XHR的AJAX封裝
 * @param {Object} options 配置對(duì)象
 * @param {string} options.url 請(qǐng)求地址
 * @param {string} [options.method='GET'] 請(qǐng)求方法
 * @param {Object} [options.data=null] 請(qǐng)求數(shù)據(jù)
 * @param {Object} [options.headers={}] 請(qǐng)求頭
 * @param {function} [options.success] 成功回調(diào)
 * @param {function} [options.error] 失敗回調(diào)
 */
function ajax(options) {
  const xhr = new XMLHttpRequest();
  const method = options.method || 'GET';
  let url = options.url;
  let data = options.data || null;

  // 處理GET請(qǐng)求的查詢參數(shù)
  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);

  // 設(shè)置請(qǐng)求頭
  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');
  };

  // 發(fā)送請(qǐng)求
  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);
  }
});

方法2. 基于 Fetch API 的封裝

/**
 * 基于Fetch API的AJAX封裝
 * @param {string} url 請(qǐng)求地址
 * @param {Object} [options={}] 請(qǐng)求配置
 * @returns {Promise} 返回Promise對(duì)象
 */
function fetchAjax(url, options = {}) {
  const defaultOptions = {
    method: 'GET',
    headers: {
      'Content-Type': 'application/json'
    },
    credentials: 'same-origin', // 攜帶cookie
    ...options
  };

  // 處理GET請(qǐng)求的查詢參數(shù)
  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請(qǐng)求的body數(shù)據(jù)
  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));

方法 3. 基于 Axios 風(fēng)格的封裝

class Ajax {
  constructor(baseURL = '', timeout = 10000) {
    this.baseURL = baseURL;
    this.timeout = timeout;
    this.interceptors = {
      request: [],
      response: []
    };
  }

  request(config) {
    // 處理請(qǐng)求攔截器
    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請(qǐng)求參數(shù)
      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);

      // 設(shè)置請(qǐng)求頭
      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'));
      };

      // 發(fā)送請(qǐng)求
      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');

// 添加請(qǐng)求攔截器
api.useRequestInterceptor(config => {
  config.headers = config.headers || {};
  config.headers['Authorization'] = 'Bearer token123';
  return config;
});

// 添加響應(yīng)攔截器
api.useResponseInterceptor(response => {
  console.log('Response:', response);
  return response.data;
}, error => {
  console.error('Error:', error);
  return Promise.reject(error);
});

// 發(fā)起請(qǐng)求
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));

4. 封裝要點(diǎn)總結(jié)

統(tǒng)一接口:提供一致的調(diào)用方式,如get(), post()等方法

參數(shù)處理:

GET請(qǐng)求自動(dòng)拼接查詢參數(shù)

POST請(qǐng)求自動(dòng)處理Content-Type

攔截器機(jī)制:支持請(qǐng)求/響應(yīng)攔截

錯(cuò)誤處理:統(tǒng)一錯(cuò)誤處理邏輯

Promise支持:返回Promise便于鏈?zhǔn)秸{(diào)用

超時(shí)處理:設(shè)置合理的請(qǐng)求超時(shí)時(shí)間

擴(kuò)展性:支持自定義配置和攔截器

5. 實(shí)際項(xiàng)目中的增強(qiáng)功能

1.自動(dòng)重試機(jī)制:

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);

2.請(qǐng)求取消功能:

function createCancelToken() {
  let cancel;
  const token = new Promise((resolve, reject) => {
    cancel = reject;
  });
  return { token, cancel };
}

// 在請(qǐng)求中檢查取消token
function ajaxWithCancel(options) {
  const { token, cancel } = createCancelToken();
  const xhr = new XMLHttpRequest();
  
  const promise = new Promise((resolve, reject) => {
    // ...正常請(qǐng)求邏輯
    
    // 檢查取消
    token.catch(err => {
      xhr.abort();
      reject(err);
    });
  });
  
  return { promise, cancel };
}

3.請(qǐng)求緩存:

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;
  });
}

根據(jù)項(xiàng)目需求選擇合適的封裝方式,小型項(xiàng)目可使用簡(jiǎn)單封裝,大型項(xiàng)目建議使用成熟的庫(kù)如Axios。

到此這篇關(guān)于AJAX常見(jiàn)的幾種封裝方法的文章就介紹到這了,更多相關(guān)AJAX封裝方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

钟山县| 绥芬河市| 报价| 丹巴县| 古丈县| 黎城县| 桐城市| 奈曼旗| 双鸭山市| 图木舒克市| 桓台县| 溧阳市| 兴义市| 北票市| 高陵县| 博兴县| 浦城县| 文昌市| 黄山市| 固始县| 抚宁县| 磴口县| 伊通| 镇远县| 称多县| 天津市| 延吉市| 阜宁县| 红桥区| 雅安市| 高青县| 龙泉市| 萨迦县| 遵义县| 临沭县| 垦利县| 边坝县| 东阳市| 武冈市| 鹤岗市| 万山特区|