欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue實現(xiàn)大文件切片上傳的示例詳解

 更新時間:2023年11月20日 09:17:10   作者:可樂加冰515  
前端上傳文件很大時,會出現(xiàn)各種問題,比如連接超時了,網(wǎng)斷了,都會導(dǎo)致上傳失敗,這個時候就需要將文件切片上傳,下面我們就來學(xué)習(xí)一下如何使用vue實現(xiàn)大文件切片上傳吧

大文件為什么要切片上傳

前端上傳文件很大時,會出現(xiàn)各種問題,比如連接超時了,網(wǎng)斷了,都會導(dǎo)致上傳失敗

服務(wù)端限制了單次上傳文件的大小

項目實際場景

客戶端需要上傳一個算法包文件到服務(wù)器,這個算法包實測 3.7G

nginx配置文件 上傳文件大小最大值為100M,

切片上傳原理

通過file.slice將大文件chunks切成許多個大小相等的chunk

將每個chunk上傳到服務(wù)器

服務(wù)端接收到許多個chunk后,合并為chunks

第一版

先對文件按指定大小進(jìn)行切片

 /**
   * file: 需要切片的文件
   * chunkSize: 每片文件大小,1024*1024=1M
   */
        chunkSlice(file, chunkSize) {
            const chunks = [],
                size = file.size,
                total = Math.ceil(size / chunkSize)
            for (let i = 0; i < size; i += chunkSize) {
                chunks.push({
                    total,
                    blob: file.slice(i, i + chunkSize),
                })
            }
            return chunks
        }

處理切片后的文件,后端想要我傳給他一個json對象,所以使用readAsDataURL讀取文件

這里使用了一個插件spark-md5來生成每個切片的MD5

        async handleFile(chunks) {
            const res = []
            for (const item of chunks) {
                const { bytes, md5 } = await this.addMark(item.blob)
                item.blob = bytes
                item.md5 = md5
                res.push(md5)
            }
            return res
        },
        // 使用FileReader讀取每一片數(shù)據(jù),并生成MD5編碼
        async addMark(chunk) {
            return new Promise((resolve, reject) => {
                const reader = new FileReader()
                const spark = new SparkMD5()

                reader.readAsDataURL(chunk)
                reader.onload = function (e) {
                    const bytes = e.target.result
                    spark.append(bytes)

                    const md5 = spark.end()
                    resolve({ bytes, md5 })
                }
            })
        },

組裝數(shù)據(jù),包括每一片的排列順序index,總共切了多少片total,文件IDfileID,每一片的md5編碼md5,每一片數(shù)據(jù)fileData

        mergeData(chunks) {
            const fileId = this.getUUID()
            const data = []
            for (let i = 0; i < chunks.length; i++) {
                const obj = {
                    fileId,
                    fileData: chunks[i].blob,//每片切片的數(shù)據(jù)
                    fileIndex: i + 1,//每片數(shù)據(jù)索引
                    fileTotal: chunks[i].total + '',
                    md5: chunks[i].md5,
                }

                data.push(obj)
            }
            return { data, fileId }
        },

上傳文件,這里使用并發(fā)上傳文件,提升文件上傳速度

const chunks = chunkSlice(file,1024*1024)
this.handleFile(chunks)
const data = this.mergeData(chunks)

for(let i = 0; i < data.length; i++){
    this.uplload(data[i])
}

第一版遇到的問題

文件太大,切片太小,上傳接口的timeout太短,并發(fā)請求時,全都在pendding,導(dǎo)致請求出錯

第一版問題解決

對上傳文件接口的timeout修改,調(diào)整時長,大一點

限制每次并發(fā)的數(shù)量,我用的是500個每次

第二版,切片 + web worker

為什么要使用web worker

在生成文件MD5編碼時,需要讀文件,是一個I/O操作,會阻塞頁面,文件太大,導(dǎo)致頁面卡死

將耗時操作轉(zhuǎn)移到worker線程,主頁面就不會卡住

vue2,使用worker

yarn add worker-loader

vue.config.js 配置

    // vue.config.js
    chainWebpack(config) {
        config.module.rule('worker')
            .test(/\.worker\.js$/)
            .use('worker-loader')
            .loader('worker-loader')
            // .options({ inline: 'fallback' })// 這個配置是個坑,不要加
    },

新建file.worker.js

// file.worker.js
import SparkMD5 from 'spark-md5'

const chunkSlice = (file, chunkSize) => {
    const chunks = [],
        size = file.size,
        total = Math.ceil(size / chunkSize)
    for (let i = 0; i < size; i += chunkSize) {
        chunks.push({
            total,
            blob: file.slice(i, i + chunkSize),
        })
    }
    return chunks
}
const handleFile = async (chunks) => {
    const res = []
    for (const item of chunks) {
        const { bytes, md5 } = await addMark(item.blob)
        item.blob = bytes
        item.md5 = md5
        res.push(md5)
    }
    return res
}
const addMark = (chunk) => {
    return new Promise((resolve, reject) => {
        const reader = new FileReader()
        const spark = new SparkMD5()

        reader.readAsDataURL(chunk)
        reader.onload = function (e) {
            const bytes = e.target.result
            spark.append(bytes)

            const md5 = spark.end()
            resolve({ bytes, md5 })
        }
    })
}
const mergeData = (chunks, fileName, options) => {
    const fileId = getUUID() // 這里更好的方式是讀整個文件的 MD5
    const data = []
    for (let i = 0; i < chunks.length; i++) {
        const obj = {
            ...options,
            suffix: '.tar.gz',
            fileId,
            fileName,
            fileData: chunks[i].blob,
            fileIndex: i + 1 + '',
            fileTotal: chunks[i].total + '',
            md5: chunks[i].md5,
        }

        data.push(obj)
    }
    return { data, fileId }
}
const getUUID = () => {
    return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
        (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16)
    )
}
const dataSlice = (data, step, fileId) => {
    const total = Math.ceil(data.length / step)
    let index = 1
    for (let i = 0; i < data.length; i += step) {
        const params = {
            type: 'workerFile',
            index,
            total,
            fileId,
            data: data.slice(i, i + step),
        }
        self.postMessage(params)
        index++
    }
}
self.addEventListener('error', (event) => {
    console.log('worker error', event)
})

self.addEventListener('message', async (event) => {
    // 確保接受的是我想要的消息  
    if (!event.data.type) return
    if (event.data.type != 'file') return
    console.log('worker success', event)

    const { file, chunkSize } = event.data
    const chunks = chunkSlice(file, chunkSize)
    const allMD5 = await handleFile(chunks)
    console.log(allMD5)
    // 此處 allMD5 可用來做后續(xù)的斷點續(xù)傳
    const { data, fileId } = mergeData(chunks, file.name)
    
    // 這里對處理好的數(shù)據(jù)進(jìn)行切片,分片傳遞給主線程,是由于 Web Worker 試圖將大量數(shù)據(jù)復(fù)制到主線程中,會導(dǎo)致內(nèi)存溢出。
    dataSlice(data, 100, fileId)

})

這個報錯一般是在使用 JavaScript Web Worker 時出現(xiàn)的,通常是由于 Web Worker 試圖將大量數(shù)據(jù)復(fù)制到主線程中,導(dǎo)致內(nèi)存溢出所引起的。

主進(jìn)程使用

// xxx.vue文件
import Worker from '@/utils/worker/file.worker.js'


const worker = new Worker()
worker.postMessage({ type: 'file', file: this.curFile, chunkSize: 1024 * 1024 })

worker.onerror = (error) => {
    console.log('main error', error)
    worker.terminate()
}

const finalData = []
worker.onmessage = async (event) => {
    console.log('main success', event)
    if (event.data.type != 'workerFile') return

    const fileId = mergeWorkerData(finalData, event.data)
    if (fileId) {
        worker.terminate()

        const status = await stepLoad(finalData, 500)

        if (!status) {
            this.$message.error('文件上傳失敗')
        } else {
            this.$message.success('文件上傳成功')

        }

    }
}

mergeWorkerData = (res, params) => {
    res.push(...params.data)
    return params.index == params.total ? params.fileId : false
}

const stepLoad = async (data, step) => {
    const res = []
    for (let i = 0; i < data.length; i += step) {
        res.push(data.slice(i, i + step))
    }
    for (const item of res) {
        const chunkRes = await Promise.all(item.map((v) => this.$api.upload(v)))
        if (chunkRes.some((v) => v.httpCode != 0)) {
            return false
        }

        const isEnd = chunkRes.filter((v) => v.finish)
        if (isEnd.length) {
            return true
        }
    }
}

總結(jié)

worker引入腳本或三方庫可以使用importScript(),但是我沒弄成功,一使用importScript()就會報錯,Renference: importScript() xxxxxxxxxxxx,如果你們弄出來了,或者知道為什么,可以在下面留言

以上就是vue實現(xiàn)大文件切片上傳的示例詳解的詳細(xì)內(nèi)容,更多關(guān)于vue大文件切片上傳的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue中使用import進(jìn)行路由懶加載的原理分析

    Vue中使用import進(jìn)行路由懶加載的原理分析

    這篇文章主要介紹了Vue中使用import進(jìn)行路由懶加載的原理分析。具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • 使用Vue3實現(xiàn)交互式雷達(dá)圖的代碼實現(xiàn)

    使用Vue3實現(xiàn)交互式雷達(dá)圖的代碼實現(xiàn)

    雷達(dá)圖是一種可視化數(shù)據(jù)的方式,用于比較多個類別中不同指標(biāo)的相對值,它適用于需要展示多個指標(biāo)之間的關(guān)系和差異的場景,本文給大家介紹了如何用Vue3輕松創(chuàng)建交互式雷達(dá)圖,需要的朋友可以參考下
    2024-06-06
  • Vue3中SetUp函數(shù)的參數(shù)props、context詳解

    Vue3中SetUp函數(shù)的參數(shù)props、context詳解

    我們知道setup函數(shù)是組合API的核心入口函數(shù),下面這篇文章主要給大家介紹了關(guān)于Vue3中SetUp函數(shù)的參數(shù)props、context的相關(guān)資料,需要的朋友可以參考下
    2021-07-07
  • Vue前端實現(xiàn)導(dǎo)出頁面為word的兩種方法

    Vue前端實現(xiàn)導(dǎo)出頁面為word的兩種方法

    這篇文章主要介紹了Vue前端實現(xiàn)導(dǎo)出頁面為word的兩種方法,文中通過代碼示例和圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-12-12
  • vue3父組件和子組件如何傳值實例詳解

    vue3父組件和子組件如何傳值實例詳解

    近期學(xué)習(xí)vue3的父子組件之間的傳值,發(fā)現(xiàn)跟vue2.x的父子組件之間的傳值并沒有太大的區(qū)別,下面這篇文章主要給大家介紹了關(guān)于vue3父組件和子組件如何傳值的相關(guān)資料,需要的朋友可以參考下
    2022-08-08
  • vue的Virtual Dom實現(xiàn)snabbdom解密

    vue的Virtual Dom實現(xiàn)snabbdom解密

    這篇文章主要介紹了vue的Virtual Dom實現(xiàn)- snabbdom解密,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Vue3框架使用報錯以及解決方案

    Vue3框架使用報錯以及解決方案

    這篇文章主要介紹了Vue3框架使用報錯以及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • vue實現(xiàn)多條件篩選超簡潔代碼

    vue實現(xiàn)多條件篩選超簡潔代碼

    這篇文章主要給大家介紹了關(guān)于vue實現(xiàn)多條件篩選的相關(guān)資料,隨著數(shù)據(jù)的不斷增多,我們往往需要在表格中進(jìn)行多條件的篩選,以便快速定位符合我們需求的數(shù)據(jù),需要的朋友可以參考下
    2023-09-09
  • vue全局組件與局部組件使用方法詳解

    vue全局組件與局部組件使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了vue全局組件與局部組件的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • vue如何將導(dǎo)航欄、頂部欄設(shè)置為公共頁面

    vue如何將導(dǎo)航欄、頂部欄設(shè)置為公共頁面

    這篇文章主要介紹了vue如何將導(dǎo)航欄、頂部欄設(shè)置為公共頁面問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01

最新評論