Appearance
异步编程
JavaScript 是单线程语言,异步编程是处理耗时操作的关键技术。
回调函数
回调函数是最基本的异步处理方式:
javascript
// setTimeout
setTimeout(function() {
console.log('1秒后执行');
}, 1000);
// 事件监听
button.addEventListener('click', function() {
console.log('按钮被点击');
});
// 回调地狱(不推荐)
getData(function(a) {
getMoreData(a, function(b) {
getMoreData(b, function(c) {
console.log(c);
});
});
});Promise
Promise 是异步编程的一种解决方案:
创建 Promise
javascript
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const success = true;
if (success) {
resolve('成功');
} else {
reject('失败');
}
}, 1000);
});使用 Promise
javascript
promise
.then(result => {
console.log('成功:', result);
return '处理后的结果';
})
.then(result => {
console.log('链式调用:', result);
})
.catch(error => {
console.error('失败:', error);
})
.finally(() => {
console.log('无论成功失败都执行');
});Promise 静态方法
javascript
// Promise.resolve
Promise.resolve('立即成功').then(console.log);
// Promise.reject
Promise.reject('立即失败').catch(console.error);
// Promise.all - 全部成功才成功
Promise.all([
fetch('/api/users'),
fetch('/api/posts')
])
.then(([users, posts]) => {
console.log(users, posts);
})
.catch(error => {
console.error('有一个失败:', error);
});
// Promise.allSettled - 等待所有完成
Promise.allSettled([
Promise.resolve(1),
Promise.reject('error'),
Promise.resolve(3)
])
.then(results => {
console.log(results);
// [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: 'error' },
// { status: 'fulfilled', value: 3 }
// ]
});
// Promise.race - 返回最快的结果
Promise.race([
fetch('/api/fast'),
fetch('/api/slow')
])
.then(result => {
console.log('最快的响应:', result);
});
// Promise.any - 返回第一个成功
Promise.any([
Promise.reject('error1'),
Promise.resolve('success'),
Promise.reject('error2')
])
.then(result => {
console.log('第一个成功:', result); // 'success'
});封装 Promise
javascript
// 封装 XMLHttpRequest
function ajax(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = () => {
if (xhr.status === 200) {
resolve(xhr.responseText);
} else {
reject(new Error(xhr.statusText));
}
};
xhr.onerror = () => reject(new Error('网络错误'));
xhr.send();
});
}
// 使用
ajax('/api/data')
.then(data => console.log(data))
.catch(error => console.error(error));async/await
async/await 是 Promise 的语法糖,让异步代码看起来像同步代码:
async 函数
javascript
async function fetchData() {
return '数据';
}
// 返回 Promise
fetchData().then(console.log); // '数据'await 表达式
javascript
async function getData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('错误:', error);
}
}并行执行
javascript
async function getParallel() {
// 串行执行(慢)
const user = await fetch('/api/user');
const posts = await fetch('/api/posts');
// 并行执行(快)
const [userRes, postsRes] = await Promise.all([
fetch('/api/user'),
fetch('/api/posts')
]);
}错误处理
javascript
async function handleError() {
try {
const data = await fetchData();
return data;
} catch (error) {
console.error('错误:', error);
throw error; // 重新抛出
}
}
// 或使用 .catch()
async function getData() {
const data = await fetchData().catch(error => {
console.error('错误:', error);
return null; // 默认值
});
return data;
}循环中的 await
javascript
// 串行执行
async function processSequential(items) {
for (const item of items) {
await processItem(item);
}
}
// 并行执行
async function processParallel(items) {
await Promise.all(items.map(item => processItem(item)));
}
// 限制并发数
async function processWithLimit(items, limit = 3) {
const results = [];
for (let i = 0; i < items.length; i += limit) {
const batch = items.slice(i, i + limit);
const batchResults = await Promise.all(
batch.map(item => processItem(item))
);
results.push(...batchResults);
}
return results;
}定时器
setTimeout
javascript
// 延迟执行
const timeoutId = setTimeout(() => {
console.log('延迟执行');
}, 1000);
// 取消
clearTimeout(timeoutId);setInterval
javascript
// 定时执行
const intervalId = setInterval(() => {
console.log('定时执行');
}, 1000);
// 取消
clearInterval(intervalId);延时函数封装
javascript
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 使用
async function example() {
console.log('开始');
await delay(1000);
console.log('1秒后');
}Fetch API
基本用法
javascript
// GET 请求
fetch('/api/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
// async/await
async function getData() {
try {
const response = await fetch('/api/data');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('请求失败:', error);
}
}POST 请求
javascript
async function postData(url, data) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
return response.json();
}
// 使用
postData('/api/users', { name: '张三', age: 25 })
.then(data => console.log(data));完整配置
javascript
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token'
},
body: JSON.stringify(data),
mode: 'cors',
credentials: 'include',
cache: 'default',
redirect: 'follow',
signal: controller.signal
});超时处理
javascript
async function fetchWithTimeout(url, timeout = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
signal: controller.signal
});
clearTimeout(timeoutId);
return response;
} catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
throw new Error('请求超时');
}
throw error;
}
}事件循环
JavaScript 使用事件循环处理异步操作:
javascript
console.log('1');
setTimeout(() => {
console.log('2');
}, 0);
Promise.resolve().then(() => {
console.log('3');
});
console.log('4');
// 输出顺序: 1, 4, 3, 2
// 同步代码 -> 微任务(Promise) -> 宏任务(setTimeout)宏任务和微任务
javascript
// 宏任务
setTimeout(() => {}, 0);
setInterval(() => {}, 0);
setImmediate(() => {}); // Node.js
requestAnimationFrame(() => {});
// 微任务
Promise.resolve().then(() => {});
queueMicrotask(() => {});
process.nextTick(() => {}); // Node.js实践示例
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>异步编程示例</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.demo-box {
padding: 20px;
background: #f8f9fa;
border-radius: 8px;
margin: 20px 0;
}
.btn {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin: 5px;
}
.btn:disabled {
background: #ccc;
cursor: not-allowed;
}
.progress {
height: 20px;
background: #e9ecef;
border-radius: 10px;
overflow: hidden;
margin: 10px 0;
}
.progress-bar {
height: 100%;
background: linear-gradient(90deg, #007bff, #0056b3);
transition: width 0.3s;
}
.result {
padding: 10px;
background: white;
border: 1px solid #ddd;
border-radius: 4px;
margin-top: 10px;
min-height: 50px;
}
.loading {
display: inline-block;
width: 20px;
height: 20px;
border: 2px solid #f3f3f3;
border-top: 2px solid #007bff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body>
<h1>异步编程示例</h1>
<h2>Promise 示例</h2>
<div class="demo-box">
<button class="btn" onclick="promiseDemo()">执行 Promise</button>
<div class="result" id="promiseResult">点击按钮查看结果</div>
</div>
<h2>async/await 示例</h2>
<div class="demo-box">
<button class="btn" id="asyncBtn" onclick="asyncDemo()">执行 async/await</button>
<div class="progress">
<div class="progress-bar" id="progressBar" style="width: 0%"></div>
</div>
<div class="result" id="asyncResult">点击按钮查看结果</div>
</div>
<h2>并行请求示例</h2>
<div class="demo-box">
<button class="btn" onclick="parallelDemo()">并行请求</button>
<button class="btn" onclick="sequentialDemo()">串行请求</button>
<div class="result" id="requestResult">点击按钮查看结果</div>
</div>
<script>
// Promise 示例
function promiseDemo() {
const result = document.getElementById('promiseResult');
result.innerHTML = '<span class="loading"></span> 执行中...';
new Promise((resolve) => {
setTimeout(() => resolve('第一步完成'), 1000);
})
.then(result => {
return new Promise(resolve => {
setTimeout(() => resolve(result + ' -> 第二步完成'), 1000);
});
})
.then(result => {
return new Promise(resolve => {
setTimeout(() => resolve(result + ' -> 第三步完成'), 1000);
});
})
.then(finalResult => {
document.getElementById('promiseResult').textContent = finalResult;
});
}
// async/await 示例
async function asyncDemo() {
const btn = document.getElementById('asyncBtn');
const progressBar = document.getElementById('progressBar');
const result = document.getElementById('asyncResult');
btn.disabled = true;
result.innerHTML = '<span class="loading"></span> 执行中...';
try {
// 模拟进度
for (let i = 0; i <= 100; i += 10) {
await delay(200);
progressBar.style.width = i + '%';
}
// 模拟数据获取
const data = await mockFetch();
result.textContent = '获取数据成功: ' + JSON.stringify(data);
} catch (error) {
result.textContent = '错误: ' + error.message;
} finally {
btn.disabled = false;
}
}
// 延时函数
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 模拟 API 请求
function mockFetch() {
return new Promise(resolve => {
setTimeout(() => {
resolve({
id: 1,
name: '张三',
email: 'zhangsan@example.com'
});
}, 500);
});
}
// 并行请求
async function parallelDemo() {
const result = document.getElementById('requestResult');
result.innerHTML = '<span class="loading"></span> 执行中...';
const start = Date.now();
const [user, posts, comments] = await Promise.all([
mockFetch(),
mockFetch(),
mockFetch()
]);
const time = Date.now() - start;
result.textContent = `并行完成,耗时: ${time}ms\n` +
`用户: ${user.name}, 文章: ${posts.id}, 评论: ${comments.id}`;
}
// 串行请求
async function sequentialDemo() {
const result = document.getElementById('requestResult');
result.innerHTML = '<span class="loading"></span> 执行中...';
const start = Date.now();
const user = await mockFetch();
const posts = await mockFetch();
const comments = await mockFetch();
const time = Date.now() - start;
result.textContent = `串行完成,耗时: ${time}ms\n` +
`用户: ${user.name}, 文章: ${posts.id}, 评论: ${comments.id}`;
}
</script>
</body>
</html>