原理逻辑
- 文件切片
首先定义每个分片的大小,然后通过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('合并成功了!!!')
})
}