文章中英模式
布鲁斯前端JS面试题目 - 实现 Promise 超时控制
学习如何实现 Promise 超时控制机制,掌握异步任务的时间管理技巧,提升前端应用稳定性与面试竞争力。
文章中英模式
懒得看文章?那就来看视频吧
Promise 超时控制概述
在实际开发中,我们经常需要为异步操作设定超时限制,避免长时间等待或无限阻塞。Promise 超时控制是一种重要的技术,可以确保应用程序的响应性和稳定性。
超时控制的重要性
- 1.
防止无限等待
:避免 Promise 永远处于 pending 状态 - 2.
提升用户体验
:及时响应用户操作,避免界面冻结 - 3.
资源管理
:防止资源泄漏和系统过载 - 4.
错误处理
:提供明确的超时错误信息
在前端面试中,实现 Promise 超时控制是测试候选人对异步处理、错误处理和时间管理理解的重要题目。
基本实现:Promise 超时控制
以下是一个基本的 Promise 超时控制实现:
// 基本 Promise 超时控制函数
function timeoutPromise(promise, timeout) {
return Promise.race([
promise,
new Promise((_, reject) => {
setTimeout(() => {
reject(new Error(`操作超时 (${timeout}ms)`));
}, timeout);
})
]);
}
// 使用示例
const fetchWithTimeout = (url, timeout = 5000) => {
return timeoutPromise(
fetch(url),
timeout
);
};
// 测试超时控制
fetchWithTimeout('https://api.example.com/data', 3000)
.then(response => response.json())
.then(data => {
console.log('数据获取成功:', data);
})
.catch(error => {
if (error.message.includes('超时')) {
console.error('请求超时,请稍后重试');
} else {
console.error('请求失败:', error);
}
});
进阶实现:可取消的 Promise
除了超时控制,我们还可以实现可取消的 Promise,提供更灵活的异步操作控制:
// 可取消的 Promise 实现
function cancellablePromise(promise) {
let isCancelled = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise
.then(result => {
if (!isCancelled) {
resolve(result);
}
})
.catch(error => {
if (!isCancelled) {
reject(error);
}
});
});
// 返回 Promise 和取消函数
return {
promise: wrappedPromise,
cancel: () => {
isCancelled = true;
}
};
}
// 结合超时和取消功能
function timeoutCancellablePromise(promise, timeout) {
const { promise: wrappedPromise, cancel } = cancellablePromise(promise);
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
cancel();
reject(new Error(`操作超时 (${timeout}ms)`));
}, timeout);
});
return Promise.race([wrappedPromise, timeoutPromise]);
}
// 使用示例
const longRunningTask = () => {
return new Promise(resolve => {
setTimeout(() => {
resolve('任务完成');
}, 10000); // 10秒
});
};
// 设定 5 秒超时
timeoutCancellablePromise(longRunningTask(), 5000)
.then(result => {
console.log('任务成功:', result);
})
.catch(error => {
console.error('任务失败:', error.message);
});
实际应用场景
Promise 超时控制在实际开发中有很多应用场景:
1. API 请求超时控制
// API 请求超时控制
class ApiClient {
constructor(baseURL, defaultTimeout = 10000) {
this.baseURL = baseURL;
this.defaultTimeout = defaultTimeout;
}
async request(endpoint, options = {}) {
const { timeout = this.defaultTimeout, ...fetchOptions } = options;
const url = `${this.baseURL}${endpoint}`;
try {
const response = await timeoutPromise(
fetch(url, fetchOptions),
timeout
);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
if (error.message.includes('超时')) {
throw new Error('请求超时,请检查网络连接');
}
throw error;
}
}
get(endpoint, timeout) {
return this.request(endpoint, { timeout });
}
post(endpoint, data, timeout) {
return this.request(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
timeout
});
}
}
// 使用示例
const apiClient = new ApiClient('https://api.example.com', 5000);
apiClient.get('/users', 3000)
.then(users => {
console.log('用户列表:', users);
})
.catch(error => {
console.error('获取用户失败:', error.message);
});
2. 用户操作超时处理
// 用户操作超时处理
class UserActionManager {
constructor() {
this.pendingActions = new Map();
}
// 执行用户操作,设定超时
async executeAction(actionId, actionPromise, timeout = 30000) {
// 如果已有相同操作在执行,先取消
if (this.pendingActions.has(actionId)) {
this.cancelAction(actionId);
}
const { promise, cancel } = cancellablePromise(actionPromise);
// 存储取消函数
this.pendingActions.set(actionId, cancel);
try {
const result = await timeoutCancellablePromise(promise, timeout);
this.pendingActions.delete(actionId);
return result;
} catch (error) {
this.pendingActions.delete(actionId);
if (error.message.includes('超时')) {
// 显示用户友好的超时提示
this.showTimeoutMessage(actionId);
}
throw error;
}
}
// 取消特定操作
cancelAction(actionId) {
const cancel = this.pendingActions.get(actionId);
if (cancel) {
cancel();
this.pendingActions.delete(actionId);
}
}
// 取消所有操作
cancelAllActions() {
this.pendingActions.forEach(cancel => cancel());
this.pendingActions.clear();
}
// 显示超时提示
showTimeoutMessage(actionId) {
console.warn(`操作 ${actionId} 超时,请稍后重试`);
// 这里可以显示 UI 提示
}
}
// 使用示例
const actionManager = new UserActionManager();
// 模拟长时间操作
const longOperation = () => {
return new Promise(resolve => {
setTimeout(() => {
resolve('操作完成');
}, 5000);
});
};
// 执行操作,设定 3 秒超时
actionManager.executeAction('upload-file', longOperation(), 3000)
.then(result => {
console.log('操作成功:', result);
})
.catch(error => {
console.error('操作失败:', error.message);
});