在JavaScript中如何处理大文件的上传与分片传输

来源:我的博客作者:北京SEO公司头衔:草根站长
导读:本期聚焦于小伙伴创作的《在JavaScript中如何处理大文件的上传与分片传输》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《在JavaScript中如何处理大文件的上传与分片传输》有用,将其分享出去将是对创作者最好的鼓励。

在JavaScript中处理大文件上传时,直接传输完整文件很容易因为网络波动、请求超时等问题导致上传失败,而且一旦失败就需要重新上传整个文件,效率极低。分片传输可以将大文件切割成多个小片段,逐个上传这些片段,既能降低单次请求的压力,也支持中断后仅上传未完成的片段,大幅提升上传的稳定性和效率。

核心相关API介绍

实现大文件分片上传主要依赖以下两个JavaScript原生API:

  • File API:用于获取用户选择的文件信息,包括文件名、大小、类型等,同时支持读取文件内容。
  • Blob.prototype.slice:Blob对象的slice方法可以截取文件的一部分,返回一个新的Blob对象,这就是实现分片的核心方法。

分片上传的整体流程

完整的大文件分片上传流程可以分为以下几个步骤:

  1. 用户选择需要上传的文件,前端获取文件的基本信息。
  2. 根据预设的分片大小,将文件切割成多个小分片。
  3. 为每个分片生成唯一标识,方便后端识别和拼接。
  4. 逐个或并发上传分片,同时记录已上传的分片信息。
  5. 所有分片上传完成后,通知后端进行分片合并。
  6. 后端合并完成后返回最终的文件地址,前端完成上传流程。

具体实现代码示例

1. 文件选择与分片切割

首先实现文件选择功能,并将选中的文件按照指定大小切割成分片:

// 分片大小设置为2MB
const CHUNK_SIZE = 2 * 1024 * 1024;
let file = null;
let chunkList = [];

// 监听文件选择事件
document.getElementById('file-input').addEventListener('change', (e) => {
    file = e.target.files[0];
    if (!file) return;
    // 切割文件为分片
    splitFileToChunks(file);
});

// 切割文件为分片的方法
function splitFileToChunks(file) {
    chunkList = [];
    // 计算总分片数
    const totalChunks = Math.ceil(file.size / CHUNK_SIZE);
    for (let i = 0; i < totalChunks; i++) {
        // 计算每个分片的起始和结束位置
        const start = i * CHUNK_SIZE;
        const end = Math.min(start + CHUNK_SIZE, file.size);
        // 截取分片
        const chunk = file.slice(start, end);
        chunkList.push({
            chunk,
            index: i,
            totalChunks,
            fileName: file.name,
            // 生成分片唯一标识,这里使用文件名+分片索引+修改时间组合
            chunkHash: `${file.name}-${i}-${file.lastModified}`
        });
    }
    console.log(`文件已切割为${totalChunks}个分片`);
}

2. 分片上传实现

接下来实现分片的上传逻辑,使用FormData携带分片数据发送给后端:

// 存储已上传的分片索引
const uploadedChunks = new Set();
// 上传单个分片的方法
function uploadSingleChunk(chunkItem) {
    const formData = new FormData();
    // 携带分片数据和相关信息
    formData.append('chunk', chunkItem.chunk);
    formData.append('chunkIndex', chunkItem.index);
    formData.append('totalChunks', chunkItem.totalChunks);
    formData.append('fileName', chunkItem.fileName);
    formData.append('chunkHash', chunkItem.chunkHash);

    return fetch('https://ipipp.com/upload-chunk', {
        method: 'POST',
        body: formData
    })
    .then(res => res.json())
    .then(data => {
        if (data.success) {
            uploadedChunks.add(chunkItem.index);
            // 更新上传进度
            updateUploadProgress();
            return true;
        }
        return false;
    })
    .catch(err => {
        console.error(`分片${chunkItem.index}上传失败`, err);
        return false;
    });
}

// 更新上传进度的方法
function updateUploadProgress() {
    const progress = (uploadedChunks.size / chunkList.length) * 100;
    document.getElementById('progress-bar').style.width = `${progress}%`;
    document.getElementById('progress-text').innerText = `上传进度:${Math.round(progress)}%`;
}

3. 并发上传与合并通知

为了提升上传效率,可以采用并发上传的方式,所有分片上传完成后通知后端合并:

// 并发上传的并发数
const CONCURRENCY = 3;

// 并发上传所有分片
async function uploadAllChunks() {
    // 将分片按并发数分组
    const chunkGroups = [];
    for (let i = 0; i < chunkList.length; i += CONCURRENCY) {
        chunkGroups.push(chunkList.slice(i, i + CONCURRENCY));
    }
    // 依次上传每组分片
    for (const group of chunkGroups) {
        const uploadPromises = group.map(chunk => uploadSingleChunk(chunk));
        await Promise.all(uploadPromises);
    }
    // 所有分片上传完成,通知后端合并
    if (uploadedChunks.size === chunkList.length) {
        mergeChunks();
    }
}

// 通知后端合并分片
function mergeChunks() {
    fetch('https://ipipp.com/merge-chunks', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            fileName: file.name,
            totalChunks: chunkList.length
        })
    })
    .then(res => res.json())
    .then(data => {
        if (data.success) {
            console.log('文件上传完成,地址:', data.fileUrl);
        }
    });
}

断点续传的实现思路

断点续传可以在上传中断后,再次上传时仅上传未完成的片段,实现思路如下:

  • 在上传分片前,先向后端查询该文件已上传的分片索引列表。
  • 前端过滤掉已上传的分片,仅上传未完成的分片。
  • 上传过程中如果中断,已上传的分片信息会保存在后端,下次上传时重复上述步骤即可。

可以在uploadAllChunks方法执行前,添加查询已上传分片的逻辑:

// 查询已上传的分片
async function getUploadedChunks(fileName) {
    const res = await fetch(`https://ipipp.com/get-uploaded-chunks?fileName=${encodeURIComponent(fileName)}`);
    const data = await res.json();
    return data.uploadedChunkIndexes || [];
}

// 修改上传所有分片的方法,加入断点续传逻辑
async function uploadAllChunks() {
    // 先查询已上传的分片
    const uploadedIndexes = await getUploadedChunks(file.name);
    uploadedIndexes.forEach(index => uploadedChunks.add(index));
    // 过滤掉已上传的分片
    const needUploadChunks = chunkList.filter(item => !uploadedChunks.has(item.index));
    // 后续上传逻辑和之前一致
    const chunkGroups = [];
    for (let i = 0; i < needUploadChunks.length; i += CONCURRENCY) {
        chunkGroups.push(needUploadChunks.slice(i, i + CONCURRENCY));
    }
    for (const group of chunkGroups) {
        const uploadPromises = group.map(chunk => uploadSingleChunk(chunk));
        await Promise.all(uploadPromises);
    }
    if (uploadedChunks.size === chunkList.length) {
        mergeChunks();
    }
}

注意事项

  • 分片大小需要合理设置,太小会导致请求数量过多,太大会失去分片的意义,一般设置为1-5MB比较合适。
  • 并发上传时需要控制并发数,避免同时发起过多请求导致浏览器限制或服务器压力过大。
  • 分片的唯一标识需要保证唯一性,避免不同文件的分片出现冲突,可以使用文件名、文件大小、修改时间、分片索引等组合生成。
  • 后端需要对应实现分片接收、存储、查询已上传分片、合并分片的逻辑,前后端接口需要提前约定好参数格式。

JavaScript大文件上传分片传输File_APIBlob修改时间:2026-06-15 18:48:52

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。