为什么你的大文件断点续传,一遇到弱网就崩溃?
当前位置:点晴教程→知识管理交流
→『 企业管理交流 』
在前端面试里,如果问到大文件上传,几乎每个人都能背出那套标准八股文:用 听起来无懈可击对吧? 但在真实的业务现场,当你的代码跑在高铁上的弱网环境、或是丢包率极高的星巴克公用 为什么看似完美的逻辑,一碰到复杂的物理网络就会碎成渣?接下来咱们聊一聊这个话题👇 常规切片上传,有什么问题?大多数网上的教程,教你的都是纯粹的玩具级代码。它们最大的问题在于:完全无视了浏览器底层的并发限制和物理网络的脆弱性。 当你对一个 首先,现代浏览器对同一个域名的 TCP 并发连接数是有严格限制的(通常是
其次,在弱网环境下,只要其中有两三个分片因为丢包而上传失败,整个 没有并发控制、没有容错重试、没有状态持久化的切片上传,就是一场灾难的开始。 简单实现原生并发队列与退回重试真正能上生产环境的上传模块,绝对不应该依赖花里胡哨的第三方大件库,而是要老老实实地用底层的 我们不需要引入庞大的状态机。利用极简的异步任务队列配合递归控制,就能在纯原生的 // 大文件切片并发上传队列控制interface ChunkTask { chunk: Blob; index: number; retryCount: number;}export async function uploadChunksWithControl( tasks: ChunkTask[], maxConcurrency = 4, // 极其克制的并发数,保护网络带宽 maxRetries = 3 // 弱网环境的重试次数): Promise<void> { let currentIndex = 0; let activeCount = 0; let hasError = false; return new Promise((resolve, reject) => { const enqueue = async () => { // 如果存在有不可恢复的重试耗尽,或者任务已经发完,直接退出 if (hasError || currentIndex >= tasks.length) { if (activeCount === 0 && !hasError) resolve(); return; } // 获取当前要处理的任务,并移动指针 const task = tasks[currentIndex++]; activeCount++; try { await uploadSingleChunk(task); } catch (err) { // 如果遇到网络抖动,不报错,而是进行静默重试 if (task.retryCount < maxRetries) { console.warn(`分片 ${task.index} 上传失败,正在进行第 ${task.retryCount + 1} 次重试...`); task.retryCount++; // 将失败任务重新插回队列末尾排队 tasks.push(task); } else { hasError = true; reject(new Error(`分片 ${task.index} 弱网重试 ${maxRetries} 次后彻底失败`)); return; // 掐断后续上传,避免资源浪费 } } finally { activeCount--; enqueue(); // 递归触发下一个空闲插槽的任务 } }; // 初始化时,填充并发池,启动指定数量的任务 for (let i = 0; i < maxConcurrency && i < tasks.length; i++) { enqueue(); } });}// 模拟单个分片的独立网络请求async function uploadSingleChunk(task: ChunkTask): Promise<void> { const formData = new FormData(); formData.append('file', task.chunk); formData.append('index', task.index.toString()); const res = await fetch('/api/upload-chunk', { method: 'POST', body: formData, }); if (!res.ok) throw new Error('Network Error');}这段代码没有任何魔法。它通过
|
关键字查询
相关文章
正在查询... |