Skip to content

ajax_fetch_lifecycle

fetch API 基于 Promises 构建。Promise 代表异步操作的最终结果。它可以处于以下三种状态之一:

  • Pending (待定): 初始状态,既未成功也未失败。
  • Fulfilled (已成功): 操作成功完成。Promise 有一个结果值。
  • Rejected (已失败): 操作失败。Promise 有一个原因(一个错误)。

您可以使用 .then() 处理成功情况,使用 .catch() 处理失败情况,以及可选的 .finally() 处理无论成功或失败都会运行的代码,以此与 Promise 交互。

`fetch('/api/data')`
`.then(response => { // Fulfilled: 网络请求成功 (即使是 404 错误!)`
`console.log('Fetch completed, status:', response.status);`
`if (!response.ok) { throw new Error('Bad response'); }`
`return response.json(); // 返回一个新的 promise`
`})`
`.then(data => { // Fulfilled: JSON 解析成功`
`console.log('Data:', data);`
`})`
`.catch(error => { // Rejected: 网络错误 或 在 .then() 中抛出的错误`
`console.error('Something went wrong:', error);`
`})`
`.finally(() => { // 可选: 在成功或失败后运行`
`console.log('Fetch attempt finished.');`
`});`

async 和 await 为 Promise 提供了语法糖,使得异步代码看起来和行为更像同步代码,许多人觉得这更容易阅读和编写。

  • async function:声明一个隐式返回 Promise 的函数。允许在其中使用 await。
  • await:暂停 async 函数的执行,直到等待的 Promise 完成(成功或失败)。如果成功,则返回解析的值。如果失败,则抛出失败原因(错误)。

使用 async/await 进行错误处理通常使用标准的 try…catch…finally 块。

async function fetchDataWithAsyncAwait(url) {
console.log('Starting fetch...'); // 开始 Fetch...
let data = null;
try {
// Await 暂停执行,直到 fetch promise 完成
const response = await fetch(url);
console.log('Response received, checking status...'); // 收到响应,正在检查状态...
// 检查 HTTP 状态 (fetch promise 会成功,即使是 4xx/5xx 错误)
if (!response.ok) {
// 抛出一个错误,将被 catch 块捕获
throw new Error(`HTTP Error: ${response.status} ${response.statusText}`);
}
console.log('Response OK, parsing JSON...'); // 响应正常,正在解析 JSON...
// Await 暂停执行,直到 response.json() promise 完成
data = await response.json();
console.log('Data parsed successfully:', data); // 数据解析成功
// 在这里使用数据
document.getElementById('output').textContent = JSON.stringify(data, null, 2);
} catch (error) {
// 捕获网络错误 (fetch rejected) 或手动抛出的错误 (例如 !response.ok)
console.error('Error during fetch operation:', error); // Fetch 操作期间发生错误
document.getElementById('output').textContent = `Error: ${error.message}`;
} finally {
// 无论 try 块成功还是失败都会运行
console.log('Fetch attempt finished.'); // Fetch 尝试完成。
}
return data; // 异步函数返回一个 promise,它将解析为该值 (如果出错则为 undefined)
}
// 示例用法
// fetchDataWithAsyncAwait('https://jsonplaceholder.typicode.com/todos/1');
// fetchDataWithAsyncAwait('https://jsonplaceholder.typicode.com/invalid-url'); // 错误示例

发出请求时,错误可能发生在不同阶段:

  • 网络错误 (Network Errors):由于网络问题(例如,DNS 查找失败、无网络连接、在请求发送之前检测到 CORS 违规)导致请求无法完成。fetch() promise 本身将失败 (reject)。
  • HTTP 错误 (HTTP Errors):服务器已响应,但状态码表示错误(例如,404 Not Found、500 Internal Server Error、401 Unauthorized)。fetch() promise 将成功 (fulfill),但 response.ok 将为 false。您需要检查 response.ok 或 response.status 并明确处理此情况(通常通过抛出错误)。
  • 解析错误 (Parsing Errors):服务器以状态 200 OK 响应,但响应体内容不是预期的格式(例如,尝试使用 response.json() 将 HTML 解析为 JSON)。读取响应体的方法(.json()、.text() 等)的 promise 将失败 (reject)。
  • 应用级错误 (Application Errors):服务器以状态 200 OK 和有效格式(例如,JSON)响应,但数据指示了一个逻辑错误(例如,{ “success”: false, “error”: “Invalid user ID” })。您需要检查响应数据本身来检测这些错误。

健壮的错误处理涉及预测这些不同的失败模式。

async function robustFetch(url) {
try {
const response = await fetch(url);
// 处理 HTTP 错误 (服务器已响应,但状态为错误)
if (!response.ok) {
let errorData;
try {
// 尝试从错误响应体获取更多详情 (通常是 JSON)
errorData = await response.json();
} catch (parseError) {
// 如果解析失败,使用状态文本
errorData = { message: response.statusText };
}
throw new Error(`HTTP ${response.status}: ${errorData.message || 'Unknown server error'}`); // 未知的服务器错误
}
// 处理解析错误
let data;
try {
data = await response.json();
} catch (parseError) {
throw new Error(`Failed to parse JSON response: ${parseError.message}`); // 解析 JSON 响应失败
}
// 处理应用级错误 (可选,取决于 API 设计)
// if (data.success === false) { // 如果数据指示逻辑失败
// throw new Error(`API Error: ${data.error}`); // API 错误
// }
console.log('Success:', data); // 成功
return data;
} catch (error) {
// 捕获网络错误 (fetch rejected) 和上面抛出的错误
console.error(`Fetch failed: ${error.message}`); // Fetch 失败
// 潜在地更新 UI 显示错误
// throw error; // 如果需要更高层级处理则重新抛出
}
}
// robustFetch('/api/resource');
// robustFetch('/api/not-found'); // 404 示例
// robustFetch('/api/invalid-json'); // 解析错误示例

关于 Promises 的更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

关于 async/await 的更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function