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

Node.js實現(xiàn)分片上傳斷點續(xù)傳示例詳解

 更新時間:2022年07月29日 09:22:18   作者:來了老弟  
這篇文章主要為大家介紹了Node.js實現(xiàn)分片上傳斷點續(xù)傳示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

正文

大文件上傳會消耗大量的時間,而且中途有可能上傳失敗。這時我們需要前端和后端配合來解決這個問題。

解決步驟:

  • 文件分片,減少每次請求消耗的時間,如果某次請求失敗可以單獨上傳,而不是從頭開始
  • 通知服務(wù)端合并文件分片
  • 控制并發(fā)的請求數(shù)量,避免瀏覽器內(nèi)存溢出
  • 當(dāng)因為網(wǎng)絡(luò)或者其他原因?qū)е履炒蔚恼埱笫?,我們重新發(fā)送請求

文件的分片與合并

在JavaScript中,F(xiàn)Ile對象是' Blob '對象的子類,該對象包含一個重要的方法slice,通過該方法我們可以這樣分割二進制文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.24.0/axios.min.js"></script>
</head>
<body>
    <input type="file" multiple="multiple" id="fileInput" />
    <button onclick="SliceUpload()">上傳</button>  
    <script>
        function SliceUpload() {
            const file = document.getElementById('fileInput').files[0]
            if (!file) return
            // 文件分片
            let size = 1024 * 50; //50KB 50KB Section size
            let fileChunks = [];
            let index = 0;        //Section num
            for (let cur = 0; cur < file.size; cur += size) {
                fileChunks.push({
                    hash: index++,
                    chunk: file.slice(cur, cur + size),
                });
            }
            // 上傳分片
            const uploadList = fileChunks.map((item, index) => {
                let formData = new FormData();
                formData.append("filename", file.name);
                formData.append("hash", item.hash);
                formData.append("chunk", item.chunk);
                return axios({
                    method: "post",
                    url: "/upload",
                    data: formData,
                });
            });
            await Promise.all(uploadList);
            // 所有分片上傳完成,通知服務(wù)器合并分片
            await axios({
                method: "get",
                url: "/merge",
                params: {
                    filename: file.name,
                },
            });
            console.log("Upload to complete");
        }
    </script>
</body>
</html>

并發(fā)控制

如果文件很大,這樣切分的分片會很多,瀏覽器短時間內(nèi)就會發(fā)起大量的請求,可能會導(dǎo)致內(nèi)存耗盡,所以要進行并發(fā)控制。

這里我們結(jié)合Promise.race()方法 控制并發(fā)請求的數(shù)量,避免瀏覽器內(nèi)存溢出。

// 加入并發(fā)控制
async function SliceUpload() {
    const file = document.getElementById('fileInput').files[0]
    if (!file) return
    // 文件分片
    let size = 1024 * 50; //50KB 50KB Section size
    let fileChunks = [];
    let index = 0;        //Section num
    for (let cur = 0; cur < file.size; cur += size) {
        fileChunks.push({
            hash: index++,
            chunk: file.slice(cur, cur + size),
        });
    }
    let pool = []; //Concurrent pool
    let max = 3; //Maximum concurrency
    for (let i = 0; i < fileChunks.length; i++) {
        let item = fileChunks[i];
        let formData = new FormData();
        formData.append("filename", file.name);
        formData.append("hash", item.hash);
        formData.append("chunk", item.chunk);
        // 上傳分片
        let task = axios({
            method: "post",
            url: "/upload",
            data: formData,
        });
        task.then(() => {
        // 從并發(fā)池中移除已經(jīng)完成的請求
        let index = pool.findIndex((t) => t === task);
            pool.splice(index);
        });
        // 把請求放入并發(fā)池中,如果已經(jīng)達到最大并發(fā)量
        pool.push(task);
        if (pool.length === max) {
            //All requests are requested complete
            await Promise.race(pool);
        }
    }
    // 所有分片上傳完成,通知服務(wù)器合并分片
    await axios({
        method: "get",
        url: "/merge",
        params: {
            filename: file.name,
        },
    });
    console.log("Upload to complete");
}

使代碼可復(fù)用

function SliceUpload() {
    const file = document.getElementById('fileInput').files[0]
    if (!file) return
    // 文件分片
    let size = 1024 * 50; // 分片大小設(shè)置
    let fileChunks = [];
    let index = 0;        // 分片序號
    for (let cur = 0; cur < file.size; cur += size) {
        fileChunks.push({
            hash: index++,
            chunk: file.slice(cur, cur + size),
        });
    }
    const uploadFileChunks = async function(list){
        if(list.length === 0){
            // 所有分片上傳完成,通知如無
            await axios({
                method: 'get',
                url: '/merge',
                params: {
                    filename: file.name
                }
            });
            console.log('Upload to complete')
            return
        }
        let pool = []       // 并發(fā)池
        let max = 3         // 最大并發(fā)數(shù)
        let finish = 0      // 完成數(shù)量
        let failList = []   // 失敗列表
        for(let i=0;i<list.length;i++){
            let item = list[i]
            let formData = new FormData()
            formData.append('filename', file.name)
            formData.append('hash', item.hash)
            formData.append('chunk', item.chunk)
            let task = axios({
                method: 'post',
                url: '/upload',
                data: formData
            })
            task.then((data)=>{
                // 從并發(fā)池中移除已經(jīng)完成的請求
                let index = pool.findIndex(t=> t===task)
                pool.splice(index)
            }).catch(()=>{
                failList.push(item)
            }).finally(()=>{
                finish++
                // 如果有失敗的重新上傳
                if(finish===list.length){
                    uploadFileChunks(failList)
                }
            })
            pool.push(task)
            if(pool.length === max){
                await Promise.race(pool)
            }
        }
    }
    uploadFileChunks(fileChunks)
}

服務(wù)端接口實現(xiàn)

const express = require('express')
const multiparty = require('multiparty')
const fs = require('fs')
const path = require('path')
const { Buffer } = require('buffer')
// file path
const STATIC_FILES = path.join(__dirname, './static/files')
// Temporary path to upload files
const STATIC_TEMPORARY = path.join(__dirname, './static/temporary')
const server = express()
// Static file hosting
server.use(express.static(path.join(__dirname, './dist')))
// Interface for uploading slices
server.post('/upload', (req, res) => {
    const form = new multiparty.Form();
    form.parse(req, function(err, fields, files) {
        let filename = fields.filename[0]
        let hash = fields.hash[0]
        let chunk = files.chunk[0]
        let dir = `${STATIC_TEMPORARY}/${filename}`
        // console.log(filename, hash, chunk)
        try {
            if (!fs.existsSync(dir)) fs.mkdirSync(dir)

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

相關(guān)文章

  • 手把手教你更優(yōu)雅的修改node_modules里的代碼

    手把手教你更優(yōu)雅的修改node_modules里的代碼

    這篇文章主要給大家介紹了關(guān)于如何更優(yōu)雅的修改node_modules里的代碼的相關(guān)資料,文中通過實例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2023-02-02
  • nodejs實現(xiàn)獲取某寶商品分類

    nodejs實現(xiàn)獲取某寶商品分類

    這篇文章主要介紹了nodejs實現(xiàn)獲取某寶商品分類,十分的簡單實用,進入后臺直接打開控制臺,把代碼粘進去運行就OK了,有需要的小伙伴可以參考下。
    2015-05-05
  • Node.js Buffer用法解讀

    Node.js Buffer用法解讀

    這篇文章主要介紹了Node.js Buffer用法解讀,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • 2014年最火的Node.JS后端框架推薦

    2014年最火的Node.JS后端框架推薦

    用nodejs開發(fā)web應(yīng)用,用哪個框架好?express?還是其他什么?今天小編就來給大家推薦一下今年最好用的幾款Node.js后端框架
    2014-10-10
  • 如何使用Node寫靜態(tài)文件服務(wù)器

    如何使用Node寫靜態(tài)文件服務(wù)器

    這篇文章主要介紹了如何使用Node寫靜態(tài)文件服務(wù)器,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,感興趣的小伙伴可以參考一下
    2022-09-09
  • Node.js API詳解之 timer模塊用法實例分析

    Node.js API詳解之 timer模塊用法實例分析

    這篇文章主要介紹了Node.js API詳解之 timer模塊用法,結(jié)合實例形式分析了Node.js API中timer模塊基本功能、原理、用法及操作注意事項,需要的朋友可以參考下
    2020-05-05
  • Nodejs爬蟲進階教程之異步并發(fā)控制

    Nodejs爬蟲進階教程之異步并發(fā)控制

    這篇文章主要介紹了Nodejs爬蟲進階教程之異步并發(fā)控制的相關(guān)資料,需要的朋友可以參考下
    2016-02-02
  • node.js實現(xiàn)BigPipe詳解

    node.js實現(xiàn)BigPipe詳解

    這篇文章主要介紹了node.js實現(xiàn)BigPipe詳解,BigPipe是 Facebook 開發(fā)的優(yōu)化網(wǎng)頁加載速度的技術(shù),BigPipe 的核心概念就是只用一個 HTTP 請求,只是頁面元素不按順序發(fā)送而已,需要的朋友可以參考下
    2014-12-12
  • 使用GruntJS構(gòu)建Web程序之合并壓縮篇

    使用GruntJS構(gòu)建Web程序之合并壓縮篇

    前一篇講述了如何使用concat和uglify命令實現(xiàn)JavaScript資源的合并,壓縮。這篇講述下css資源的合并和壓縮。
    2014-06-06
  • nodejs安裝與配置過程+初學(xué)實例解讀

    nodejs安裝與配置過程+初學(xué)實例解讀

    這篇文章主要介紹了nodejs安裝與配置過程+初學(xué)實例解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04

最新評論