JavaScript 快速入门

异步编程与网络请求

JavaScript 是单线程的,异步编程允许程序在等待某些操作完成的同时继续执行其他代码,如网络请求、文件读写等。本章将介绍 JavaScript 中的异步编程和网络请求。

回调函数

回调函数是异步编程的最基本形式,它作为参数传递给另一个函数,并在特定事件发生时被调用。

// 基本回调函数
function fetchData(callback) {
setTimeout(() => {
const data = { id: 1, name: '张三' };
callback(data);
}, 1000);
}
fetchData(data => {
console.log('获取到数据:', data);
});
// 错误处理回调
function fetchDataWithError(successCallback, errorCallback) {
setTimeout(() => {
const random = Math.random();
if (random > 0.5) {
const data = { id: 1, name: '张三' };
successCallback(data);
} else {
errorCallback(new Error('获取数据失败'));
}
}, 1000);
}
fetchDataWithError(
data => console.log('获取到数据:', data),
error => console.error('错误:', error.message)
);

回调地狱

当有多个异步操作需要按顺序执行时,使用回调函数会导致代码嵌套过深,形成"回调地狱"。

// 回调地狱示例
function step1(callback) {
setTimeout(() => {
console.log('步骤1完成');
callback();
}, 1000);
}
function step2(callback) {
setTimeout(() => {
console.log('步骤2完成');
callback();
}, 1000);
}
function step3(callback) {
setTimeout(() => {
console.log('步骤3完成');
callback();
}, 1000);
}
// 嵌套回调
step1(() => {
step2(() => {
step3(() => {
console.log('所有步骤完成');
});
});
});

Promise 对象

Promise 是处理异步操作的一种更现代的方式,它提供了更清晰的语法和更好的错误处理机制。

基本用法

// 创建 Promise
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const random = Math.random();
if (random > 0.5) {
resolve({ id: 1, name: '张三' });
} else {
reject(new Error('获取数据失败'));
}
}, 1000);
});
// 使用 Promise
promise
.then(data => {
console.log('获取到数据:', data);
return data.id; // 返回一个值,传递给下一个 then
})
.then(id => {
console.log('用户ID:', id);
})
.catch(error => {
console.error('错误:', error.message);
})
.finally(() => {
console.log('无论成功或失败都会执行');
});

Promise 链

Promise 可以通过链式调用处理多个异步操作。

function fetchUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ id, name: '张三' });
}, 1000);
});
}
function fetchUserPosts(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve([
{ id: 1, title: '文章1', userId },
{ id: 2, title: '文章2', userId }
]);
}, 1000);
});
}
function fetchPostComments(postId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve([
{ id: 1, text: '评论1', postId },
{ id: 2, text: '评论2', postId }
]);
}, 1000);
});
}
// Promise 链
fetchUser(1)
.then(user => {
console.log('获取到用户:', user);
return fetchUserPosts(user.id);
})
.then(posts => {
console.log('获取到文章:', posts);
return fetchPostComments(posts[0].id);
})
.then(comments => {
console.log('获取到评论:', comments);
})
.catch(error => {
console.error('错误:', error.message);
});

Promise 静态方法

Promise 提供了一些静态方法来处理多个 Promise。

// Promise.all - 等待所有 Promise 完成
const promise1 = Promise.resolve(1);
const promise2 = new Promise(resolve => setTimeout(() => resolve(2), 1000));
const promise3 = new Promise(resolve => setTimeout(() => resolve(3), 2000));
Promise.all([promise1, promise2, promise3])
.then(values => {
console.log('所有 Promise 完成:', values); // [1, 2, 3]
})
.catch(error => {
console.error('错误:', error.message);
});
// Promise.race - 等待第一个 Promise 完成
Promise.race([promise1, promise2, promise3])
.then(value => {
console.log('第一个完成的 Promise:', value); // 1
})
.catch(error => {
console.error('错误:', error.message);
});
// Promise.allSettled - 等待所有 Promise 完成,无论成功或失败
const promise4 = Promise.reject(new Error('失败'));
Promise.allSettled([promise1, promise2, promise3, promise4])
.then(results => {
console.log('所有 Promise 已解决:', results);
// [
// { status: 'fulfilled', value: 1 },
// { status: 'fulfilled', value: 2 },
// { status: 'fulfilled', value: 3 },
// { status: 'rejected', reason: Error: 失败 }
// ]
});

async/await 语法

async/await 是基于 Promise 的语法糖,它使异步代码看起来更像同步代码,更易于理解和维护。

基本用法

// 定义异步函数
async function fetchData() {
try {
const response = await new Promise((resolve, reject) => {
setTimeout(() => {
const random = Math.random();
if (random > 0.5) {
resolve({ id: 1, name: '张三' });
} else {
reject(new Error('获取数据失败'));
}
}, 1000);
});
console.log('获取到数据:', response);
return response;
} catch (error) {
console.error('错误:', error.message);
throw error; // 重新抛出错误
}
}
// 调用异步函数
fetchData()
.then(data => {
console.log('处理数据:', data);
})
.catch(error => {
console.error('处理错误:', error.message);
});

并行执行

可以使用 Promise.all 和 async/await 并行执行多个异步操作。

async function fetchUserAndPosts(userId) {
try {
// 并行执行两个异步操作
const [user, posts] = await Promise.all([
fetchUser(userId),
fetchUserPosts(userId)
]);
console.log('用户:', user);
console.log('文章:', posts);
return { user, posts };
} catch (error) {
console.error('错误:', error.message);
throw error;
}
}
fetchUserAndPosts(1)
.then(result => {
console.log('获取成功:', result);
})
.catch(error => {
console.error('获取失败:', error.message);
});

串行执行

async/await 使串行执行多个异步操作变得简单。

async function processUserData(userId) {
try {
// 串行执行异步操作
const user = await fetchUser(userId);
console.log('获取到用户:', user);
const posts = await fetchUserPosts(user.id);
console.log('获取到文章:', posts);
const comments = await fetchPostComments(posts[0].id);
console.log('获取到评论:', comments);
return { user, posts, comments };
} catch (error) {
console.error('处理用户数据时出错:', error.message);
throw error;
}
}
processUserData(1)
.then(result => {
console.log('处理成功:', result);
})
.catch(error => {
console.error('处理失败:', error.message);
});

Fetch 请求

Fetch API 是一种现代的、基于 Promise 的网络请求接口,用于在浏览器中发送 HTTP 请求。

发送 GET 请求

// 发送 GET 请求
fetch('https://api.example.com/users')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP 错误! 状态: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log('获取到数据:', data);
})
.catch(error => {
console.error('请求失败:', error.message);
});
// 使用 async/await
async function fetchUsers() {
try {
const response = await fetch('https://api.example.com/users');
if (!response.ok) {
throw new Error(`HTTP 错误! 状态: ${response.status}`);
}
const data = await response.json();
console.log('获取到数据:', data);
return data;
} catch (error) {
console.error('请求失败:', error.message);
throw error;
}
}

发送 POST 请求

// 发送 POST 请求
const userData = {
name: '张三',
email: 'zhangsan@example.com'
};
fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(userData)
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP 错误! 状态: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log('创建成功:', data);
})
.catch(error => {
console.error('创建失败:', error.message);
});
// 使用 async/await
async function createUser(userData) {
try {
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(userData)
});
if (!response.ok) {
throw new Error(`HTTP 错误! 状态: ${response.status}`);
}
const data = await response.json();
console.log('创建成功:', data);
return data;
} catch (error) {
console.error('创建失败:', error.message);
throw error;
}
}

动手试试

练习 1:实现一个简单的 Promise 工具函数

实现一个 retry 函数,它接受一个返回 Promise 的函数和最大重试次数,当 Promise 失败时自动重试。

练习 2:模拟网络请求

创建一个函数,模拟从服务器获取用户数据,使用 Promise 实现。函数应该有一个参数表示是否模拟请求失败,并在控制台输出结果。

练习 3:串行与并行请求

创建三个函数,分别模拟获取用户信息、用户文章和文章评论。然后实现两种方式获取数据:串行(一个接一个)和并行(同时请求)。

Made by 捣鼓键盘的小麦 / © 2025 Front Study 版权所有