要在 fetch API 中手动实现超时机制和进度机制,可以结合使用 AbortController
和 ReadableStream
。以下是详细的实现步骤:
实现超时机制
使用 AbortController
来实现超时机制。AbortController
可以用于中止一个 fetch
请求。
实现进度机制
使用 ReadableStream
来实现进度机制。通过读取响应流并计算已加载的数据量,可以实现进度更新。
完整示例
以下是一个完整的示例,展示如何在 fetch
中手动实现超时机制和进度机制:
async function fetchWithTimeoutAndProgress(url, options = {}, timeout = 5000, onProgress) {
const controller = new AbortController();
const { signal } = controller;
const fetchOptions = { ...options, signal };
// 设置超时
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, fetchOptions);
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const contentLength = response.headers.get('content-length');
if (!contentLength) {
throw new Error('Content-Length response header unavailable');
}
const total = parseInt(contentLength, 10);
let loaded = 0;
const reader = response.body.getReader();
const stream = new ReadableStream({
start(controller) {
function push() {
reader.read().then(({ done, value }) => {
if (done) {
controller.close();
return;
}
loaded += value.byteLength;
onProgress((loaded / total) * 100);
controller.enqueue(value);
push();
}).catch(error => {
console.error('Stream error:', error);
controller.error(error);
});
}
push();
}
});
const newResponse = new Response(stream);
return newResponse.text();
} catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
throw new Error('Request timed out');
}
throw error;
}
}
// 使用示例
fetchWithTimeoutAndProgress(
'https://jsonplaceholder.typicode.com/posts',
{},
5000,
(progress) => {
console.log(`Progress: ${progress}%`);
}
)
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
解释
- 超时机制:
- 使用 AbortController 创建一个控制器,并将其信号传递给 fetch 请求。
- 使用 setTimeout 在指定时间后调用 controller.abort() 来中止请求。
- 在请求完成或发生错误时,使用 clearTimeout 清除超时。
- 进度机制:
- 获取响应的 content-length 头信息来确定总数据大小。
- 使用 ReadableStream 和 response.body.getReader() 读取响应流。
- 在读取过程中,计算已加载的数据量,并调用 onProgress 回调函数更新进度。
注意事项
- 错误处理:确保在捕获错误时清除超时,并处理 AbortError。
- 浏览器兼容性:ReadableStream 和 AbortController 是现代浏览器的特性,确保你的目标浏览器支持这些特性。