Skip to content

AJAX 事件

处理异步操作:Promises 和 Async/Await

Section titled “处理异步操作:Promises 和 Async/Await”

现代 JavaScript 严重依赖 Promise 和 async/await 语法来管理网络请求(Fetch API)、定时器等异步操作。这提供了一种比基于旧式回调的模式更清晰、更易于管理的替代方案。

Promise 是一个对象,代表异步操作最终完成(或失败)及其结果值。

Promise 可以处于以下三种状态之一:

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

Fetch API 返回 Promise。你可以使用 .then()、.catch() 和 .finally() 方法与它们进行交互。

  • .then(onFulfilled, onRejected):为成功和失败状态附加回调函数。通常,你使用 .then(onFulfilled) 处理成功情况,然后链式调用 .catch(onRejected) 处理错误。

  • .catch(onRejected):仅为失败状态附加回调函数。捕获来自前一个 Promise 或链中任何 .then() 回调的错误。

  • .finally(onFinally):附加一个回调函数,该函数无论 Promise 成功还是失败都会执行(例如,用于清理工作)。

使用 Fetch 和 Promises 的示例:
console.log('Starting fetch...');
fetch('https://api.example.com/data')
.then(response => {
console.log('Received response object.');
if (!response.ok) {
// If status code is not OK, create an error to be caught by .catch()
throw new Error(`Network response was not ok: ${response.status}`);
}
return response.json(); // Returns another Promise
})
.then(data => {
console.log('Data parsed successfully:', data);
// Update UI with data
document.getElementById('content').innerText = JSON.stringify(data, null, 2);
})
.catch(error => {
console.error('Fetch operation failed:', error);
// Display error message
document.getElementById('content').innerText = `Error: ${error.message}`;
})
.finally(() => {
console.log('Fetch attempt finished (either success or failure).');
// Hide loading indicator, etc.
});
console.log('Fetch initiated, but code continues executing...');

注意 .then() 处理器是如何链式调用的。每个 .then() 都会接收前一个 Promise 或回调的结果。

async/await 是基于 Promises 构建的语法糖,它允许你编写看起来和行为上更像同步代码的异步代码,使其更容易阅读和维护。

  • async function:使用 async 关键字声明一个函数意味着它将自动返回一个 Promise。该 Promise 的 resolved 值将是该函数返回的任何值。

  • await:await 运算符只能在 async function 内部使用。它会暂停 async function 的执行,直到它等待的 Promise 状态确定(成功或失败)。如果成功,它返回 resolved 值。如果失败,它抛出错误。

使用 `async/await` 重写的上一个示例:
async function fetchData() {
const contentElement = document.getElementById('content');
console.log('Starting fetch...');
try {
const response = await fetch('https://api.example.com/data');
console.log('Received response object.');
if (!response.ok) {
throw new Error(`Network response was not ok: ${response.status}`);
}
const data = await response.json(); // Wait for JSON parsing
console.log('Data parsed successfully:', data);
// Update UI with data
contentElement.innerText = JSON.stringify(data, null, 2);
} catch (error) {
// Errors from fetch() or thrown manually are caught here
console.error('Fetch operation failed:', error);
contentElement.innerText = `Error: ${error.message}`;
} finally {
console.log('Fetch attempt finished (either success or failure).');
// Hide loading indicator, etc.
}
}
console.log('Calling fetchData...');
fetchData(); // Call the async function
console.log('fetchData called, but code continues executing...');

async/await 的主要优点:

  • 可读性:看起来比嵌套的 .then() 链清晰得多。
  • 错误处理:可以使用标准的 try...catch 块来处理 awaited Promises 中的错误。
  • 调试:在调试器中单步执行 await 调用通常更直观。

遗留技术:XMLHttpRequest 和 onreadystatechange

Section titled “遗留技术:XMLHttpRequest 和 onreadystatechange”

在 Fetch 和 Promises 出现之前,XMLHttpRequest (XHR) 是发起异步请求的主要方式。它采用基于事件的方法。

onreadystatechange 事件处理程序在请求生命周期中会被多次调用,指示 readyState 属性的变化。

属性描述
onreadystatechange存储一个函数,该函数在 readyState 属性改变时被调用。
readyState保存 XMLHttpRequest 的状态。从 0 变到 4:
0: 请求未初始化
1: 服务器连接已建立
2: 请求已接收
3: 正在处理请求
4: 请求已完成且响应已就绪
status保存 HTTP 状态码(例如,200 表示 “OK”,404 表示 “Not Found”),该值在请求完成后(即 readyState 为 4 时)可用。

典型的 XHR 模式是在 onreadystatechange 处理程序内部检查 readyState 是否为 4 且 status 是否为 200:

// --- LEGACY EXAMPLE --- Not recommended for new code ---
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
// Check if the request is complete and was successful
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// Success!
console.log('XHR Success:', xhr.responseText);
document.getElementById('myDiv').innerHTML = xhr.responseText;
} else {
// Error (e.g., 404, 500)
console.error('XHR Error:', xhr.status, xhr.statusText);
document.getElementById('myDiv').innerHTML = 'Error loading data.';
}
}
};
// Configure the request (GET request to 'data.txt')
xhr.open('GET', 'data.txt', true); // true makes it asynchronous
// Optional: Handle network errors
xhr.onerror = function() {
console.error('XHR Network Error occurred');
};
// Send the request
xhr.send();

虽然你可能在旧的代码库中遇到 XHR,但由于其更简洁的语法和与现代 JavaScript 特性的更好集成,Fetch API 结合 Promises 或 async/await 是新开发的标准。