异步设计模式
JavaScript异步编程是前端开发的核心技能,掌握异步设计模式是构建高性能应用的关键。
异步基础模式
回调模式
JavaScript
// 基础回调
function fetchData(url, callback) {
setTimeout(() => {
callback(null, { data: 'result' });
}, 1000);
}
// 错误优先回调(Node.js风格)
fetchData('/api', (error, data) => {
if (error) {
console.error(error);
return;
}
console.log(data);
});
// 回调地狱问题
fetchUser(userId, (error, user) => {
fetchOrders(user.id, (error, orders) => {
fetchOrderDetails(orders[0].id, (error, details) => {
// 嵌套层级过深
});
});
});
Promise模式
JavaScript
// Promise封装
function fetchData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ data: 'result' });
}, 1000);
});
}
// 链式调用解决回调地狱
fetchUser(userId)
.then(user => fetchOrders(user.id))
.then(orders => fetchOrderDetails(orders[0].id))
.then(details => console.log(details))
.catch(error => console.error(error));
// 并行处理
Promise.all([
fetchUser(userId),
fetchOrders(userId),
fetchNotifications(userId)
]).then(([user, orders, notifications]) => {
// 全部完成
});
// 竞争处理
Promise.race([
fetchFromServer1(),
fetchFromServer2()
]).then(result => {
// 第一个完成的结果
});
Async/Await模式
JavaScript
// 基础语法
async function fetchUserOrders(userId) {
try {
const user = await fetchUser(userId);
const orders = await fetchOrders(user.id);
return orders;
} catch (error) {
console.error('Error:', error);
throw error;
}
}
// 并行执行
async function fetchAll(userId) {
const [user, orders, notifications] = await Promise.all([
fetchUser(userId),
fetchOrders(userId),
fetchNotifications(userId)
]);
return { user, orders, notifications };
}
异步流程控制模式
异步队列模式
JavaScript
class AsyncQueue {
constructor(concurrency = 1) {
this.concurrency = concurrency;
this.running = 0;
this.queue = [];
}
async add(task) {
return new Promise((resolve, reject) => {
this.queue.push({ task, resolve, reject });
this.process();
});
}
async process() {
while (this.running < this.concurrency && this.queue.length > 0) {
this.running++;
const { task, resolve, reject } = this.queue.shift();
try {
const result = await task();
resolve(result);
} catch (error) {
reject(error);
} finally {
this.running--;
this.process();
}
}
}
}
// 使用:限制并发数
const queue = new AsyncQueue(3);
for (let i = 0; i < 10; i++) {
queue.add(() => fetchData(`/api/${i}`));
}
异步重试模式
JavaScript
async function retry(fn, options = {}) {
const { maxRetries = 3, delay = 1000, backoff = 2 } = options;
let lastError;
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
lastError = error;
if (i < maxRetries - 1) {
await sleep(delay * Math.pow(backoff, i));
}
}
}
throw lastError;
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 使用
await retry(() => fetchData('/api/data'), {
maxRetries: 3,
delay: 500,
backoff: 2
});
超时控制模式
JavaScript
// Promise超时
function withTimeout(promise, ms) {
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Timeout')), ms);
});
return Promise.race([promise, timeout]);
}
// 使用
try {
const data = await withTimeout(fetchData('/api'), 5000);
} catch (error) {
if (error.message === 'Timeout') {
console.log('请求超时');
}
}
// AbortController取消
async function fetchWithAbort(url, signal) {
const response = await fetch(url, { signal });
return response.json();
}
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);
try {
await fetchWithAbort('/api/data', controller.signal);
} catch (error) {
if (error.name === 'AbortError') {
console.log('请求已取消');
}
}
高级异步模式
异步迭代器模式
JavaScript
// 异步生成器
async function* fetchPaginatedData(baseUrl) {
let page = 1;
let hasMore = true;
while (hasMore) {
const response = await fetch(`${baseUrl}?page=${page}`);
const data = await response.json();
yield* data.items;
hasMore = data.hasMore;
page++;
}
}
// 使用
for await (const item of fetchPaginatedData('/api/items')) {
console.log(item);
}
// 异步迭代器类
class AsyncDataIterator {
constructor(fetcher) {
this.fetcher = fetcher;
this.index = 0;
this.data = [];
}
[Symbol.asyncIterator]() {
return {
next: async () => {
if (this.index >= this.data.length) {
this.data = await this.fetcher();
this.index = 0;
}
if (this.data.length === 0) {
return { done: true };
}
return { value: this.data[this.index++], done: false };
}
};
}
}
异步事件发射器
JavaScript
class AsyncEventEmitter {
constructor() {
this.events = new Map();
}
on(event, handler) {
if (!this.events.has(event)) {
this.events.set(event, []);
}
this.events.get(event).push(handler);
}
async emit(event, ...args) {
const handlers = this.events.get(event) || [];
await Promise.all(handlers.map(handler => handler(...args)));
}
once(event, handler) {
const wrapper = async (...args) => {
await handler(...args);
this.off(event, wrapper);
};
this.on(event, wrapper);
}
off(event, handler) {
const handlers = this.events.get(event);
if (handlers) {
const index = handlers.indexOf(handler);
if (index > -1) handlers.splice(index, 1);
}
}
}
// 使用
const emitter = new AsyncEventEmitter();
emitter.on('data', async (data) => {
await process(data);
});
await emitter.emit('data', { id: 1 });
异步缓存模式
JavaScript
class AsyncCache {
constructor(fetcher, ttl = 60000) {
this.fetcher = fetcher;
this.ttl = ttl;
this.cache = new Map();
this.pending = new Map();
}
async get(key) {
const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp < this.ttl) {
return cached.value;
}
// 防止重复请求
if (this.pending.has(key)) {
return this.pending.get(key);
}
const promise = this.fetcher(key).then(value => {
this.cache.set(key, { value, timestamp: Date.now() });
this.pending.delete(key);
return value;
});
this.pending.set(key, promise);
return promise;
}
invalidate(key) {
this.cache.delete(key);
}
}
// 使用
const cache = new AsyncCache(fetchData, 30000);
const data1 = await cache.get('user-1'); // 发起请求
const data2 = await cache.get('user-1'); // 返回缓存
并发控制模式
并发池
JavaScript
async function pool(tasks, concurrency) {
const results = [];
const executing = new Set();
for (const task of tasks) {
const promise = Promise.resolve().then(() => task());
results.push(promise);
executing.add(promise);
const cleanup = () => executing.delete(promise);
promise.then(cleanup, cleanup);
if (executing.size >= concurrency) {
await Promise.race(executing);
}
}
return Promise.all(results);
}
// 使用:同时最多执行3个任务
const tasks = urls.map(url => () => fetch(url));
const results = await pool(tasks, 3);
节流与防抖
JavaScript
// 防抖:延迟执行,重复调用重置计时
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 节流:固定间隔执行
function throttle(fn, interval) {
let lastTime = 0;
return function (...args) {
const now = Date.now();
if (now - lastTime >= interval) {
lastTime = now;
return fn.apply(this, args);
}
};
}
// 异步节流:保证上一个完成后再执行
async function asyncThrottle(fn, interval) {
let lastTime = 0;
let pending = false;
return async function (...args) {
if (pending) return;
const now = Date.now();
if (now - lastTime < interval) {
return;
}
pending = true;
try {
lastTime = Date.now();
return await fn.apply(this, args);
} finally {
pending = false;
}
};
}
要点总结
- 回调→Promise→Async/Await:异步编程演进,代码更简洁
- 异步队列:控制并发数,避免资源耗尽
- 重试机制:提高可靠性,配合退避策略
- 超时控制:防止无限等待,AbortController可取消
- 异步迭代器:处理分页、流式数据的利器
- 并发池:高效处理批量异步任务
存放路径:articles/JS/专家/设计模式与架构思想/异步设计模式.md
📝 发现内容有误?点击此处直接编辑