尝试把以前一些很晕的概念连起来…

什么是AJAX?

  • AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
  • AJAX是一种在Web应用中通过异步发送HTTP请求向服务器获取内容,并使用这些新内容更新页面中相关部分,而无需中心加载整个页面的Web开发技术,这可以让页面更具响应性,因为只请求了需要更新的部分。
  • 起初,AJAX通过使用XMLHttpRequest接口实现,但是现在,fetch() API更适合用于开发现代Web应用。

XMLHttpRequest:AJAX的最初实现

  • 虽然叫XMLHttpRequest,但是它可以用于请求任何类型的数据,而不仅仅是XML。
  • 甚至支持HTTP以外的协议,比如file和ftp。但是可能受到更多出于安全等原因的限制。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 1. 创建实例化对象
const xhr = new XMLHttpRequest();
// 2. 初始化请求
xhr.open("GET", "/api/user");
// 3, 当readyState属性改变时触发
xhr.onreadystatechange = function () {
// 4. states代表请求的响应状态
if (xhr.readyState === 4 && xhr.status === 200) {
// 5. 解析响应数据
const data = JSON.parse(xhr.responseText);
console.log(data);
}
};

// 6. 发送请求
xhr.send();
  • 还有一些其他的属性和方法:
    • responseText:返回请求的响应文本
    • responseXML:返回请求的响应XML文档
    • responseURL:返回请求的响应URL
    • timeout:设置请求的超时时间
    • upload:返回一个XMLHttpRequestUpload对象,用于表示上传的进度
    • withCredentials:设置是否携带跨域凭证
    • abort():取消请求

Promise:更优雅的异步处理

  • 在进入fetch()这个现代化实现AJAX之前,我们先来看看Promise。
  • Promise是一种更优雅的异步处理方式,它是一个对象,代表一个异步操作的最终完成或失败以及其结果值。
  • fetch正是基于Promise实现的。

如果没有Promise,我们需要在一开始把回调函数作为参数传入函数中,一个回调函数在成功时被调用,另一个则在异常时被调用。

1
2
3
4
5
6
7
8
9
function successCallback(result) {
console.log("成功:" + result);
}

function failureCallback(error) {
console.log("失败:" + error);
}

doSomething(settings, successCallback, failureCallback);

但是如果我们重写doSomething()函数,使其返回一个Promise对象,我们就可以使用then()方法来处理成功和失败的情况。

1
doSomething(settings).then(successCallback, failureCallback);

那么这种写法有什么好处呢?

链式调用

如果我们需要连续执行两个或者多个异步操作,在上一个操作执行成功之后,开始下一个操作,并带着上一步操作返回的结果,在旧的回调风格中会导致经典的回调地狱。

1
2
3
4
5
6
7
doSomething(settings, function (result) {
doSomethingElse(result, function (newResult) {
doThirdThing(newResult, function (finalResult) {
console.log('Got the final result: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);

而在Promise中,我们可以使用then()方法来解决这个问题。因为回调函数是附加到Promise对象上,而不是传入一个函数中的。then()方法返回一个
新的Promise对象

then的回调函数传入的参数是上一个Promise对象的resolve()方法传入的参数。
如果上一个then的回调函数返回的只是一个普通的值,那么下一个then的回调函数的参数就是这个值。
而then函数返回的是一个新的Promise对象,所以可以继续调用then方法。但是兑现值往往是undefined。
如果上一个处理器启动了一个Promise但是没有返回,那么就没办法再追踪它的敲定状态了,这个Promise就是漂浮的。
一个经验法则是操作每次遇到一个Promise就返回它,并把它的处理推迟到下一个then服务器中

1
2
3
4
5
6
7
doSomething(settings)
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);

那么doSomething()函数是如何返回一个Promise对象的呢?

1
2
3
4
5
6
7
8
9
10
function doSomething(settings) {
return new Promise((resolve, reject) => {
// 异步操作
if (/* 异步操作成功 */) {
resolve('成功');
} else {
reject('失败');
}
});
}

async/await是Promise的语法糖,可以让我们更优雅地处理异步操作。

1
2
3
4
5
6
7
8
9
10
async function foo() {
try {
const result = await doSomething(settings);
const newResult = await doSomethingElse(result);
const finalResult = await doThirdThing(newResult);
console.log('Got the final result: ' + finalResult);
} catch (error) {
failureCallback(error);
}
}

2. 组合

Promise.all
我们可以同时启动所有操作,再等待它们全部完成。

如果数组中的某个Promise被拒绝,Promise.all返回的Promise会立即被拒绝,并终止其他操作。

1
2
3
4
5
Promise.all([doSomething(), doSomethingElse(), doThirdThing()])
.then(([result1, result2, result3]) => {
console.log('Got the final result: ' + result3);
})
.catch(failureCallback);

fetch():现代化的AJAX实现

  • fetch 是对 XHR 的替代,是浏览器原生支持的基于 Promise 的 HTTP 客户端。
  • Window接口的fetch()方法用于发起获取资源的请求,他会返回一个会在请求响应后兑现的promise。
  • 该promise会兑现一个表示请求响应的Response对象。
  • 当请求失败时,fetch()的promise才会被拒绝。fetch()的promise不会因为服务器响应表示错误的HTTP码(404、500等)
    而被拒绝,因此then()处理器必须检查Response.ok或Response.status属性。
1
2
3
4
5
6
7
8
9
10
11
12
13
fetch('/api/user')
.then(response => {
if (!response.ok) {
throw new Error('请求失败');
}
return response.json();
})
.then(data => {
console.log(data);
})
.catch(error => {
console.log(error);
});

如果换成我们刚刚提到的async/await,那么代码会更加简洁。

1
2
3
4
5
6
7
8
9
10
11
12
async function foo() {
try {
const response = await fetch('/api/user');
if (!response.ok) {
throw new Error('请求失败');
}
const data = await response.json();
console.log(data);
} catch (error) {
console.log(error);
}
}

Axios:更强大的AJAX库

  • Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。
  • 特点:
    • 支持Promise API
    • 请求和响应拦截器
    • 转换请求和响应数据
    • 取消请求
    • 自动转换JSON数据
    • 客户端支持防止CSRF(跨站请求伪造)
1
2
3
4
5
6
7
axios.get('/api/user')
.then(response => {
console.log(response.data);
})
.catch(error => {
console.log(error);
});

具体的方法还有很多,比如post、put、delete,参照官方文档链接:Axios

拦截器

  • axios的一大特点就是拦截器。
  • 请求拦截器:在请求被发送之前拦截它们,可以用来修改请求的配置信息。
  • 响应拦截器:在响应被 then 或 catch 处理前拦截它们,可以用来修改响应的数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 添加请求拦截器
axios.interceptors.request.use(config => {
// 在发送请求之前做些什么
return config;
}, error => {
// 对请求错误做些什么
return Promise.reject(error);
});

// 添加响应拦截器
axios.interceptors.response.use(response => {
// 对响应数据做点什么
return response;
}, error => {
// 对响应错误做点什么
return Promise.reject(error);
});

// 移除拦截器
axios.interceptors.request.eject(myInterceptor);

1.❓什么是 AJAX?它的作用是什么?

答:

AJAX 是 Asynchronous JavaScript and XML 的缩写,指的是在网页无需重新加载的情况下,通过 JavaScript 异步发送 HTTP 请求并获取数据,从而局部更新页面内容的一种技术方案。它提升了用户体验,使页面响应更快、交互更自然。

2.XMLHttpRequest 是什么?是不是只能请求 XML?

答:

XMLHttpRequest(XHR)是浏览器早期用于实现 AJAX 的核心 API,尽管名字中包含 XML,但它可以请求任何类型的数据,比如 JSON、HTML、纯文本、图片等。XHR 支持 GET、POST 等 HTTP 请求,具备请求状态管理、取消、设置超时、跨域凭证等功能。

3.Promise 的核心概念是什么?有哪几种状态?

答:

Promise 是 ES6 提供的一种用于管理异步操作的机制。它代表一个将来可能完成或失败的操作及其结果。

Promise 有三种状态:

  • pending:初始状态,未完成
  • fulfilled:操作成功完成
  • rejected:操作失败

Promise 提供 .then().catch() 方法来注册成功或失败的回调。

4.Promise 和回调函数的区别?为什么推荐 Promise?

答:

传统异步用回调函数处理,但多层嵌套容易出现“回调地狱”;Promise 通过链式调用 .then(),让异步流程更清晰、更可控,且支持统一错误处理。Promise 是更现代的异步抽象,结合 async/await 更像同步代码。

5.什么是 then() 的返回值?链式调用是如何实现的?

答:

每个 .then() 方法会返回一个新的 Promise,这个新的 Promise 的状态由 .then() 回调函数的返回值决定。如果返回的是普通值,该值会传给下一个 .then();如果返回的是 Promise,则会等待它完成后再传递其结果。

6.什么是 async/await?和 Promise 有什么关系?

答:

async/await 是基于 Promise 的语法糖:

  • async 用于定义一个异步函数,它返回一个 Promise。
  • await 用于等待一个 Promise 完成,它会暂停当前函数,直到 Promise 完成,并返回结果

它让异步流程写法更接近同步代码,可读性更强。

7.await Promise.all() 是什么?应用场景是什么?

答:

Promise.all([p1, p2, ...]) 会并发执行所有 Promise,只有当全部 Promise 成功时,结果才会返回为一个数组,按顺序对应每个任务结果。若有一个失败,则整个 Promise.all 立即 reject,常用于多个接口并发加载。

8.fetch 和 XMLHttpRequest 有什么区别?

答:

特性 fetch XMLHttpRequest
是否原生 Promise ✅ 是 ❌ 否,需要手动封装
是否支持拦截器 ❌ 不支持 ❌ 不支持
错误处理 仅网络错误会 reject HTTP 错误需手动处理
语法简洁 ✅ 使用更现代语法 ❌ 写法复杂

fetch 是浏览器对 XHR 的现代替代方案,语法基于 Promise,更清晰,但不自动处理 HTTP 错误。

9.axios 是什么?它和 fetch 的区别是什么?

答:

axios 是一个第三方 HTTP 客户端库,在浏览器中基于 XHR,在 Node.js 中基于 http 模块。它封装了很多高级功能,比如:

  • 自动 JSON 转换
  • 请求和响应拦截器
  • 请求超时控制
  • 支持取消请求
  • 统一错误处理

相比之下,fetch 是浏览器内置 API,更轻量,但功能基础。

10.axios 如何设置请求/响应拦截器?常用场景有哪些?

答:

拦截器是 axios 提供的中间层机制:

1
2
3
4
5
6
7
8
9
10
axios.interceptors.request.use(config => {
config.headers.Authorization = 'Bearer token';
return config;
});

axios.interceptors.response.use(response => {
return response.data;
}, error => {
return Promise.reject(error);
});

常见应用:

  • 请求前统一添加 token
  • 响应后统一剥离结构(只返回 data)
  • 错误状态统一弹窗或跳转

11.axios 为什么被称为“HTTP 客户端”?

答:

因为它的职责是“发起 HTTP 请求并处理响应”,这正是客户端行为(请求方)的定义。HTTP 客户端包括:浏览器、Postman、curl、axios。它们不监听端口、不处理传入请求,只是发出请求。

12.axios 和 fetch 都是 XMLHttpRequest 的封装吗?

答:

  • fetch:不是封装,而是原生替代(浏览器新内核实现)
  • axios:在浏览器中基于 XMLHttpRequest 实现,在 Node 中则用 http 模块

可以认为 axios 是对 XHR 的更高级封装,提供统一接口。

13.fetch 为什么要调用两次 .then() 才能拿到数据?

答:

fetch 第一次 .then() 返回的是 Response 对象,必须调用 response.json().text() 等方法才能读取真正的数据。因为 response.body 是可读流,要异步解析。

1
2
3
fetch('/api/user')
.then(res => res.json()) // 第一次解包
.then(data => console.log(data)); // 真正的数据

14.axios 默认会处理哪些事情?fetch 要手动做什么?

功能 axios ✅(自动) fetch ❌(手动)
JSON 自动解析 res.data ❌ 要 .json()
HTTP 错误抛异常 ✅ 自动进入 catch ❌ 需手动 res.ok 判断
设置请求头 ✅ 自动设 Content-Type ❌ 需手动设置
请求超时 ✅ 支持 timeout ❌ 需自封装
请求取消 ✅ 支持 CancelToken ✅ 支持 AbortController(较新)

15.写一个 async 函数调用 axios 请求,并加上错误处理?

答:

1
2
3
4
5
6
7
8
async function getUser() {
try {
const res = await axios.get('/api/user');
console.log(res.data);
} catch (error) {
console.error('请求失败', error.message);
}
}

16.解释下这段代码的流程:

1
2
3
fetch('/api/user')
.then(response => response.json())
.then(data => console.log(data));

答:

  • fetch 发出 HTTP 请求,返回一个 Promise<Response>
  • 第一个 .then() 处理响应,将 response.body 解析为 JSON,返回 Promise<object>
  • 第二个 .then() 拿到 JSON 数据,打印结果