返回顶部
分享到

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

相关技巧 来源:互联网 作者:佚名 发布时间:2025-08-02 06:51:48 人浏览
摘要

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

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

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

XMLHttpRequest。其主要特点如下:

  1. 实现动态不刷新,通过异步?式,提升?户体验,优化了浏览器和服务器之间的传输。
  2. 把?部分原本由服务器负担的?作转移到客户端,利?客户端闲置的资源进?处理,减轻服务器和带宽的负担,节约空间和成本。
  3. ?刷新更新??,?户不?再像以前?样在服务器处理数据时,只能在死板的?屏前焦急的等待。AJAX使?XMLHttpRequest对象发送请求并得到服务器响应,在不需要重新载?整个??的情况下,就可以通过DOM及时将更新的内容显示在??上。

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

/**

 * 基于原生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);

  }

});

方法2. 基于 Fetch API 的封装

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

/**

 * 基于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));

方法 3. 基于 Axios 风格的封装

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

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

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

4. 封装要点总结

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

参数处理:

GET请求自动拼接查询参数

POST请求自动处理Content-Type

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

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

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

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

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

5. 实际项目中的增强功能

1.自动重试机制:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

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.请求取消功能:

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

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

}

3.请求缓存:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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。


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 :
相关文章
  • AJAX常见的几种封装方法实例

    AJAX常见的几种封装方法实例
    AJAX (Asynchronous JavaScript and XML) 封装是为了简化重复的异步请求代码,提高开发效率和代码复用性。下面我将介绍几种常见的 AJAX 封装方式。
  • 修改git commit的author信息实现方式
    修改git commit的author信息 本地有多个git账号时,容易发生忘记设置项目默认账号,最后以全局账号提交的情况,其实对代码本身并无影响,只
  • 在VSCode中使用Git进行版本控制的实现

    在VSCode中使用Git进行版本控制的实现
    在 VS Code 中使用 Git 进行版本控制 参考: Using Version Control in VS Code 初始化(init) 功能:将文件夹初始化为git仓库(实际就是在文件夹下创建一个
  • Grafana安装配置介绍

    Grafana安装配置介绍
    一、查看操作系统 二、下载 用户需要根据当前操作系统,到 Grafana 官网下载安装包,并执行安装。 下载地址如下:https://grafana.com/grafana/
  • Git Commit Message写错问题的解决方案

    Git Commit Message写错问题的解决方案
    作为一名开发者,提交代码时写错Commit Message是常见问题。今天就讲一下如何修改本地和远程仓库的Commit Message,重点解决已Push到远程仓库的
  • 用自写的jQuery库+Ajax实现了省市联动功能

    用自写的jQuery库+Ajax实现了省市联动功能
    1. 省市联动: 在网页上,选择对应的省份之后,动态的关联出该省份对应的市。选择对应的市之后,动态地关联出城市对应的区。 2. 设计数
  • 在Postman中高效生成随机环境变量的三种高效方法
    为什么需要随机环境变量? 在API测试中,随机数据解决了几个关键问题: 避免重复数据冲突:防止因唯一性约束导致的测试失败 模拟真实
  • 一文介绍php、jsp、asp和aspx的区别(小科普)
    通俗理解 PHP 通俗:PHP就像万能胶,专为快速搭建中小型网站设计。它语法简单(类似C语言),免费且跨平台,适合新手和中小项目,比如
  • Trae AI IDE的使用教程(全网最全)

    Trae AI IDE的使用教程(全网最全)
    Trae AI IDE 全网最全的使用教程 近期,字节发布了一款 AI Coding 产品 Trae,它是一款对标 Cursor 和 Windsurf 的全新 IDE,也是一款真正为中文开发
  • AJAX常见的几种封装方法实例介绍

    AJAX常见的几种封装方法实例介绍
    AJAX (Asynchronous JavaScript and XML) 封装是为了简化重复的异步请求代码,提高开发效率和代码复用性。下面我将介绍几种常见的 AJAX 封装方式。
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计