亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

vue?大文件分片上傳(斷點續(xù)傳、并發(fā)上傳、秒傳)

 更新時間:2022年07月08日 08:54:32   作者:小小猴沖刺  
本文主要介紹了vue?大文件分片上傳,主要包括斷點續(xù)傳、并發(fā)上傳、秒傳,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

對于大文件的處理,無論是用戶端還是服務(wù)端,如果一次性進(jìn)行讀取發(fā)送、接收都是不可取,很容易導(dǎo)致內(nèi)存問題。所以對于大文件上傳,采用切塊分段上傳,從上傳的效率來看,利用多線程并發(fā)上傳能夠達(dá)到最大效率。

本文是基于 springboot + vue 實現(xiàn)的文件上傳,本文主要介紹vue實現(xiàn)文件上傳的步驟及代碼實現(xiàn),服務(wù)端(springboot)的實現(xiàn)步驟及實現(xiàn)請移步本人的另一篇文章:

springboot 大文件上傳、分片上傳、斷點續(xù)傳、秒傳 

上傳分步:

本人分析上傳總共分為:

  • MD5讀取文件,獲取文件的MD5編碼
  • 請求服務(wù)端判斷文件是否上傳,如上傳完成就直接返回文件地址
  • 如未上傳,判斷是否是斷點續(xù)傳
  • 判斷是并發(fā)上傳還是順序上傳
  • 開始分片文件上傳,分片上傳完成后寫入已上傳列表中
  • 判斷是否上傳完成

直接上代碼

文件上傳:

import md5 from 'js-md5' //引入MD5加密
import UpApi from '@/api/common.js'
import { concurrentExecution } from '@/utils/jnxh'
?
/**
?* 文件分片上傳
?* @params file {File} 文件
?* @params pieceSize {Number} 分片大小 默認(rèn)3MB
?* @params concurrent {Number} 并發(fā)數(shù)量 默認(rèn)2
?* @params process {Function} 進(jìn)度回調(diào)函數(shù)
?* @params success {Function} 成功回調(diào)函數(shù)
?* @params error {Function} 失敗回調(diào)函數(shù)
?*/
export const uploadByPieces = ({
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?file,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?pieceSize = 3,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?concurrent = 3,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?success,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?process,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?error
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}) => {
? // 如果文件傳入為空直接 return 返回
? if (!file || file.length < 1) {
? ? return error('文件不能為空')
? }
? let fileMD5 = '' // 總文件列表
? const chunkSize = pieceSize * 1024 * 1024 // 1MB一片
? const chunkCount = Math.ceil(file.size / chunkSize) // 總片數(shù)
? const chunkList = [] // 分片列表
? let uploaded = [] // 已經(jīng)上傳的
? let fileType = '' // 文件類型
? // 獲取md5
? /***
? ?* 獲取md5
? ?**/
? const readFileMD5 = () => {
? ? // 讀取視頻文件的md5
? ? fileType = file.name.substring(file.name.lastIndexOf('.') + 1, file.name.length)
? ? console.log('獲取文件的MD5值')
? ? let fileRederInstance = new FileReader()
? ? console.log('file', file)
? ? fileRederInstance.readAsBinaryString(file)
? ? fileRederInstance.addEventListener('load', e => {
? ? ? let fileBolb = e.target.result
? ? ? fileMD5 = md5(fileBolb)
? ? ? var index = file.name.lastIndexOf('.')
? ? ? var tp = file.name.substring(index + 1, file.name.length)
? ? ? let form = new FormData()
? ? ? form.append('filename', file.name)
? ? ? form.append('identifier', fileMD5)
? ? ? form.append('objectType', fileType)
? ? ? form.append('chunkNumber', 1)
? ? ? UpApi.uploadChunk(form).then(res => {
? ? ? ? if (res.skipUpload) {
? ? ? ? ? console.log('文件已被上傳')
? ? ? ? ? success && success(res)
? ? ? ? } else {
? ? ? ? ? // 判斷是否是斷點續(xù)傳
? ? ? ? ? if (res.uploaded && res.uploaded.length != 0) {
? ? ? ? ? ? uploaded = [].concat(res.uploaded)
? ? ? ? ? }
? ? ? ? ? console.log('已上傳的分片:' + uploaded)
? ? ? ? ? // 判斷是并發(fā)上傳或順序上傳
? ? ? ? ? if (concurrent == 1 || chunkCount == 1) {
? ? ? ? ? ? console.log('順序上傳')
? ? ? ? ? ? sequentialUplode(0)
? ? ? ? ? } else {
? ? ? ? ? ? console.log('并發(fā)上傳')
? ? ? ? ? ? concurrentUpload()
? ? ? ? ? }
? ? ? ? }
? ? ? }).catch((e) => {
? ? ? ? console.log('文件合并錯誤')
? ? ? ? console.log(e)
? ? ? })
? ? })
? }
? /***
? ?* 獲取每一個分片的詳情
? ?**/
? const getChunkInfo = (file, currentChunk, chunkSize) => {
? ? let start = currentChunk * chunkSize
? ? let end = Math.min(file.size, start + chunkSize)
? ? let chunk = file.slice(start, end)
? ? return {
? ? ? start,
? ? ? end,
? ? ? chunk
? ? }
? }
? /***
? ?* 針對每個文件進(jìn)行chunk處理
? ?**/
? const readChunkMD5 = () => {
? ? // 針對單個文件進(jìn)行chunk上傳
? ? for (var i = 0; i < chunkCount; i++) {
? ? ? const {
? ? ? ? chunk
? ? ? } = getChunkInfo(file, i, chunkSize)
?
? ? ? // 判斷已經(jīng)上傳的分片中是否包含當(dāng)前分片
? ? ? if (uploaded.indexOf(i + '') == -1) {
? ? ? ? uploadChunk({
? ? ? ? ? chunk,
? ? ? ? ? currentChunk: i,
? ? ? ? ? chunkCount
? ? ? ? })
? ? ? }
? ? }
? }
? /***
? ?* 原始上傳
? ?**/
? const uploadChunk = (chunkInfo) => {
? ? var sd = parseInt((chunkInfo.currentChunk / chunkInfo.chunkCount) * 100)
? ? console.log(sd, '進(jìn)度')
? ? process(sd)
? ? console.log(chunkInfo, '分片大小')
? ? let inde = chunkInfo.currentChunk + 1
? ? if (uploaded.indexOf(inde + '') > -1) {
? ? ? const {
? ? ? ? chunk
? ? ? } = getChunkInfo(file, chunkInfo.currentChunk + 1, chunkSize)
? ? ? uploadChunk({
? ? ? ? chunk,
? ? ? ? currentChunk: inde,
? ? ? ? chunkCount
? ? ? })
? ? } else {
? ? ? var index = file.name.lastIndexOf('.')
? ? ? var tp = file.name.substring(index + 1, file.name.length)
? ? ? // 構(gòu)建上傳文件的formData
? ? ? let fetchForm = new FormData()
? ? ? fetchForm.append('identifier', fileMD5)
? ? ? fetchForm.append('chunkNumber', chunkInfo.currentChunk + 1)
? ? ? fetchForm.append('chunkSize', chunkSize)
? ? ? fetchForm.append('currentChunkSize', chunkInfo.chunk.size)
? ? ? const chunkfile = new File([chunkInfo.chunk], file.name)
? ? ? fetchForm.append('file', chunkfile)
? ? ? // fetchForm.append('file', chunkInfo.chunk)
? ? ? fetchForm.append('filename', file.name)
? ? ? fetchForm.append('relativePath', file.name)
? ? ? fetchForm.append('totalChunks', chunkInfo.chunkCount)
? ? ? fetchForm.append('totalSize', file.size)
? ? ? fetchForm.append('objectType', tp)
? ? ? // 執(zhí)行分片上傳
? ? ? let config = {
? ? ? ? headers: {
? ? ? ? ? 'Content-Type': 'application/json',
? ? ? ? ? 'Accept': '*/*'
? ? ? ? }
? ? ? }
?
? ? ? UpApi.uploadChunk(fetchForm, config).then(res => {
?
? ? ? ? if (res.code == 200) {
? ? ? ? ? console.log('分片上傳成功')
? ? ? ? ? uploaded.push(chunkInfo.currentChunk + 1)
? ? ? ? ? // 判斷是否全部上傳完
? ? ? ? ? if (uploaded.length == chunkInfo.chunkCount) {
? ? ? ? ? ? console.log('全部完成')
? ? ? ? ? ? success(res)
? ? ? ? ? ? process(100)
? ? ? ? ? } else {
? ? ? ? ? ? const {
? ? ? ? ? ? ? chunk
? ? ? ? ? ? } = getChunkInfo(file, chunkInfo.currentChunk + 1, chunkSize)
? ? ? ? ? ? uploadChunk({
? ? ? ? ? ? ? chunk,
? ? ? ? ? ? ? currentChunk: chunkInfo.currentChunk + 1,
? ? ? ? ? ? ? chunkCount
? ? ? ? ? ? })
? ? ? ? ? }
?
? ? ? ? } else {
? ? ? ? ? console.log(res.msg)
? ? ? ? }
?
? ? ? }).catch((e) => {
? ? ? ? error && error(e)
? ? ? })
? ? ? // if (chunkInfo.currentChunk < chunkInfo.chunkCount) {
? ? ? // ? setTimeout(() => {
? ? ? //
? ? ? // ? }, 1000)
? ? ? // }
? ? }
? }
? /***
? ?* 順序上傳
? ?**/
? const sequentialUplode = (currentChunk) => {
? ? const {
? ? ? chunk
? ? } = getChunkInfo(file, currentChunk, chunkSize)
? ? let chunkInfo = {
? ? ? chunk,
? ? ? currentChunk,
? ? ? chunkCount
? ? }
? ? var sd = parseInt((chunkInfo.currentChunk / chunkInfo.chunkCount) * 100)
? ? process(sd)
? ? console.log('當(dāng)前上傳分片:' + currentChunk)
? ? let inde = chunkInfo.currentChunk + 1
? ? if (uploaded.indexOf(inde + '') > -1) {
? ? ? console.log('分片【' + currentChunk + '】已上傳')
? ? ? sequentialUplode(currentChunk + 1)
? ? } else {
? ? ? let uploadData = createUploadData(chunkInfo)
? ? ? let config = {
? ? ? ? headers: {
? ? ? ? ? 'Content-Type': 'application/json',
? ? ? ? ? 'Accept': '*/*'
? ? ? ? }
? ? ? }
? ? ? // 執(zhí)行分片上傳
? ? ? UpApi.uploadChunk(uploadData, config).then(res => {
? ? ? ? if (res.code == 200) {
? ? ? ? ? console.log('分片【' + currentChunk + '】上傳成功')
? ? ? ? ? uploaded.push(chunkInfo.currentChunk + 1)
? ? ? ? ? // 判斷是否全部上傳完
? ? ? ? ? if (uploaded.length == chunkInfo.chunkCount) {
? ? ? ? ? ? console.log('全部完成')
? ? ? ? ? ? success(res)
? ? ? ? ? ? process(100)
? ? ? ? ? } else {
? ? ? ? ? ? sequentialUplode(currentChunk + 1)
? ? ? ? ? }
?
? ? ? ? } else {
? ? ? ? ? console.log(res.msg)
? ? ? ? }
?
? ? ? }).catch((e) => {
? ? ? ? error && error(e)
? ? ? })
? ? }
? }
? /***
? ?* 并發(fā)上傳
? ?**/
? const concurrentUpload = () => {
? ? for (var i = 0; i < chunkCount; i++) {
? ? ? chunkList.push(Number(i))
? ? }
? ? console.log('需要上傳的分片列表:' + chunkList)
? ? concurrentExecution(chunkList, concurrent, (curItem) => {
? ? ? return new Promise((resolve, reject) => {
? ? ? ? const {
? ? ? ? ? chunk
? ? ? ? } = getChunkInfo(file, curItem, chunkSize)
? ? ? ? let chunkInfo = {
? ? ? ? ? chunk,
? ? ? ? ? currentChunk: curItem,
? ? ? ? ? chunkCount
? ? ? ? }
? ? ? ? var sd = parseInt((chunkInfo.currentChunk / chunkInfo.chunkCount) * 100)
? ? ? ? process(sd)
? ? ? ? console.log('當(dāng)前上傳分片:' + curItem)
? ? ? ? let inde = chunkInfo.currentChunk + 1
? ? ? ? if (uploaded.indexOf(inde + '') == -1) {
? ? ? ? ? // 構(gòu)建上傳文件的formData
? ? ? ? ? let uploadData = createUploadData(chunkInfo)
? ? ? ? ? // 請求頭
? ? ? ? ? let config = {
? ? ? ? ? ? headers: {
? ? ? ? ? ? ? 'Content-Type': 'application/json',
? ? ? ? ? ? ? 'Accept': '*/*'
? ? ? ? ? ? }
? ? ? ? ? }
? ? ? ? ? UpApi.uploadChunk(uploadData, config).then(res => {
? ? ? ? ? ? if (res.code == 200) {
? ? ? ? ? ? ? uploaded.push(chunkInfo.currentChunk + 1)
? ? ? ? ? ? ? console.log('已經(jīng)上傳完成的分片:' + uploaded)
? ? ? ? ? ? ? // 判斷是否全部上傳完
? ? ? ? ? ? ? if (uploaded.length == chunkInfo.chunkCount) {
? ? ? ? ? ? ? ? success(res)
? ? ? ? ? ? ? ? process(100)
? ? ? ? ? ? ? }
? ? ? ? ? ? ? resolve()
? ? ? ? ? ? } else {
? ? ? ? ? ? ? reject(res)
? ? ? ? ? ? ? console.log(res.msg)
? ? ? ? ? ? }
?
? ? ? ? ? }).catch((e) => {
? ? ? ? ? ? reject(res)
? ? ? ? ? ? error && error(e)
? ? ? ? ? })
? ? ? ? } else {
? ? ? ? ? console.log('分片【' + chunkInfo.currentChunk + '】已上傳')
? ? ? ? ? resolve()
? ? ? ? }
? ? ? })
? ? }).then(res => {
? ? ? console.log('finish', res)
? ? })
? }
? /***
? ?* 創(chuàng)建文件上傳參數(shù)
? ?**/
? const createUploadData = (chunkInfo) => {
? ? let fetchForm = new FormData()
? ? fetchForm.append('identifier', fileMD5)
? ? fetchForm.append('chunkNumber', chunkInfo.currentChunk + 1)
? ? fetchForm.append('chunkSize', chunkSize)
? ? fetchForm.append('currentChunkSize', chunkInfo.chunk.size)
? ? const chunkfile = new File([chunkInfo.chunk], file.name)
? ? fetchForm.append('file', chunkfile)
? ? // fetchForm.append('file', chunkInfo.chunk)
? ? fetchForm.append('filename', file.name)
? ? fetchForm.append('relativePath', file.name)
? ? fetchForm.append('totalChunks', chunkInfo.chunkCount)
? ? fetchForm.append('totalSize', file.size)
? ? fetchForm.append('objectType', fileType)
? ? return fetchForm
? }
? readFileMD5() // 開始執(zhí)行代碼
}

并發(fā)控制:

/**
 * 并發(fā)執(zhí)行
 * @params list {Array} - 要迭代的數(shù)組
 * @params limit {Number} - 并發(fā)數(shù)量控制數(shù),最好小于3
 * @params asyncHandle {Function} - 對`list`的每一個項的處理函數(shù),參數(shù)為當(dāng)前處理項,必須 return 一個Promise來確定是否繼續(xù)進(jìn)行迭代
 * @return {Promise} - 返回一個 Promise 值來確認(rèn)所有數(shù)據(jù)是否迭代完成
 */
export function concurrentExecution(list, limit, asyncHandle) {
  // 遞歸執(zhí)行
  let recursion = (arr) => {
    // 執(zhí)行方法 arr.shift() 取出并移除第一個數(shù)據(jù)
    return asyncHandle(arr.shift()).then(() => {
      // 數(shù)組還未迭代完,遞歸繼續(xù)進(jìn)行迭代
      if (arr.length !== 0) {
        return recursion(arr)
      } else {
        return 'finish'
      }
    })
  }
  // 創(chuàng)建新的并發(fā)數(shù)組
  let listCopy = [].concat(list)
  // 正在進(jìn)行的所有并發(fā)異步操作
  let asyncList = []
  limit = limit > listCopy.length ? listCopy.length : limit
  console.log(limit)
  while (limit--) {
    asyncList.push(recursion(listCopy))
  }
  // 所有并發(fā)異步操作都完成后,本次并發(fā)控制迭代完成
  return Promise.all(asyncList)
}

到此這篇關(guān)于vue 大文件分片上傳(斷點續(xù)傳、并發(fā)上傳、秒傳)的文章就介紹到這了,更多相關(guān)vue 大文件分片上傳內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 封裝一下vue中的axios示例代碼詳解

    封裝一下vue中的axios示例代碼詳解

    這篇文章主要介紹了封裝一下vue中的axios,本文通過示例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-02-02
  • vue結(jié)合leaflet實現(xiàn)鷹眼圖

    vue結(jié)合leaflet實現(xiàn)鷹眼圖

    本文主要介紹了vue結(jié)合leaflet實現(xiàn)鷹眼圖,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • vue中的搜索關(guān)鍵字實例講解

    vue中的搜索關(guān)鍵字實例講解

    這篇文章主要介紹了vue中的搜索關(guān)鍵字實例講解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • vue 虛擬DOM的原理

    vue 虛擬DOM的原理

    這篇文章主要介紹了vue 虛擬DOM的原理,幫助大家更好的理解和學(xué)習(xí)vue,感興趣的朋友可以了解下
    2020-10-10
  • Vue動態(tài)修改網(wǎng)頁標(biāo)題的方法及遇到問題

    Vue動態(tài)修改網(wǎng)頁標(biāo)題的方法及遇到問題

    Vue下有很多的方式去修改網(wǎng)頁標(biāo)題,這里總結(jié)下解決此問題的幾種方案:,需要的朋友可以參考下
    2019-06-06
  • el-menu遞歸實現(xiàn)多級菜單組件的示例

    el-menu遞歸實現(xiàn)多級菜單組件的示例

    本文主要介紹了el-menu使用遞歸組件實現(xiàn)多級菜單組件,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • 詳解關(guān)于element el-button使用$attrs的一個注意要點

    詳解關(guān)于element el-button使用$attrs的一個注意要點

    這篇文章主要介紹了詳解關(guān)于element el-button使用$attrs的一個注意要點,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • vue初嘗試--項目結(jié)構(gòu)(推薦)

    vue初嘗試--項目結(jié)構(gòu)(推薦)

    這篇文章主要介紹了vue初嘗試--項目結(jié)構(gòu)的相關(guān)知識,需要的朋友可以參考下
    2018-01-01
  • Vue實現(xiàn)搖一搖功能(兼容ios13.3以上)

    Vue實現(xiàn)搖一搖功能(兼容ios13.3以上)

    這篇文章主要為大家詳細(xì)介紹了Vue實現(xiàn)搖一搖功能,兼容ios13.3以上,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-01-01
  • vue 查看dist文件里的結(jié)構(gòu)(多種方式)

    vue 查看dist文件里的結(jié)構(gòu)(多種方式)

    本文通過三種方式給大家介紹了vue 查看dist文件里的結(jié)構(gòu),非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-01-01

最新評論