前端分片上传

141 阅读1分钟

原理逻辑

  • 文件切片

首先定义每个分片的大小,然后通过slice()方法对文件分片,最后将分片数组进行存储

  • md5计算

1、第一个和最后一个切片全部参与计算

2.中间的切片只计算前面两个字节、中间两个字节、最后两个字节,得到一个数组

3.通过SparkMD5计算得到一个hash值,作为该文件的文件名,保证不重复

  • 发起检查请求,把当前文件的hash发送给服务端,检查是否有相同hash的文件
  • 上传分片

根据切片数组和hash值通过map格式化得到一个formData文件,该文件每个对象包含文件hash值、分片hash,以及分片内容。然后设置一个请求池,并非请求数量设置为6个,只有有一个完成就往里再添加一个知道所有分片上传完毕。最后再通过服务器进行合并文件

 const uploadChunks = async (chunks, existChunks) => {
                const data = chunks
                    .filter(item => !existChunks.includes(item.chunkHash))
                    .map((chunk, index) => {
                        return {
                            fileHash: fileHash.value,
                            chunkHash: fileHash.value + '-' + index,
                            chunk
                        }
                    })
                const formDatas = data.map((item) => {
                    const formData = new FormData()
                    formData.append('fileHash', item.fileHash)
                    formData.append(' chunkHash', item.chunkHash)
                    formData.append(' chunk', item.chunk)
                    return formData
                })
                const max = 6  //最大并发请求数
                let index = 0
                const taskPool = []    //请求池
                while (index < formDatas.length) {
                    const task = fetch('/upload ', {
                        method: 'POST',
                        body: formDatas[index]
                    })
                    taskPool.splice(taskPool.findIndex((item) => item === task))
                    taskPool.push(task)
                    if (taskPool.length == max) {
                        await Promise.race(taskPool)
                    }
                    index++
                }
                await Promise.all(taskPool)
                // 通知服务器去合并文件
                margeRequest()
            }
  • 上传完成后通知后端合并切片
 const margeRequest = () => {
                fetch('http:// localhost: 3000/merge', {
                    method: 'POST',
                    headers: {
                        'content-type': 'application/json',
                    },
                    body: JSON.stringify({
                        fileHash: fileHash.value, fileName: fileName.value, size: CHUNK_SIZE
                    })
                }).then(res => {
                    alert('合并成功了!!!')
                })
            }