Bagaimana untuk melaksanakan muat naik berbilang bahagian dalam Node.js? Pengenalan kaedah

青灯夜游
Lepaskan: 2022-07-29 20:22:17
ke hadapan
1728 orang telah melayarinya

NodBagaimana untuk melaksanakan muat naik berbilang bahagian? Artikel berikut akan memperkenalkan kepada anda cara melaksanakan muat naik berbilang bahagian dalam Node.js saya harap ia akan membantu anda!

Bagaimana untuk melaksanakan muat naik berbilang bahagian dalam Node.js? Pengenalan kaedah

Memuat naik fail besar akan memakan banyak masa dan muat naik mungkin gagal di pertengahan jalan. Pada masa ini kita memerlukan bahagian hadapan dan belakang untuk bekerjasama bagi menyelesaikan masalah ini.

Langkah penyelesaian:

  • Pemecahan fail untuk mengurangkan masa yang digunakan oleh setiap permintaan Jika permintaan gagal, anda boleh memuat naiknya secara berasingan dan bukannya bermula dari awal

  • Beritahu pelayan untuk menggabungkan serpihan fail

  • Kawal bilangan permintaan serentak untuk mengelakkan limpahan memori penyemak imbas

  • Apabila permintaan gagal kerana rangkaian atau sebab lain, kami menghantar semula permintaan itu

Pemecahan dan penggabungan fail

Dalam JavaScript, objek FIle ialah subkelas objek 'Blob', yang mengandungi kepingan kaedah penting, yang melaluinya kita boleh membahagikan fail binari seperti ini:

<!DOCTYPE html>
<html>
<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);

            // 所有分片上传完成,通知服务器合并分片
            await axios({
                method: "get",
                url: "/merge",
                params: {
                    filename: file.name,
                },
            });
            console.log("Upload to complete");
        }
    </script>
</body>
</html>
Salin selepas log masuk

Concurrency Control

Jika fail itu besar, terdapat banyak serpihan yang dibahagikan dengan cara ini dan penyemak imbas akan memulakan sejumlah besar permintaan dalam tempoh yang singkat, yang mungkin menyebabkan kehabisan memori, jadi kawalan serentak diperlukan.

Di sini kami menggabungkan kaedah Promise.race() untuk mengawal bilangan permintaan serentak dan mengelakkan limpahan memori penyemak imbas.

// 加入并发控制
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(() => {
        // 从并发池中移除已经完成的请求
        let index = pool.findIndex((t) => t === task);
            pool.splice(index);
        });

        // 把请求放入并发池中,如果已经达到最大并发量
        pool.push(task);
        if (pool.length === max) {
            //All requests are requested complete
            await Promise.race(pool);
        }
    }

    // 所有分片上传完成,通知服务器合并分片
    await axios({
        method: "get",
        url: "/merge",
        params: {
            filename: file.name,
        },
    });
    console.log("Upload to complete");
}
Salin selepas log masuk

Jadikan kod boleh diguna semula

function SliceUpload() {
    const file = document.getElementById('fileInput').files[0]
    if (!file) return

    // 文件分片
    let size = 1024 * 50; // 分片大小设置
    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: &#39;get&#39;,
                url: &#39;/merge&#39;,
                params: {
                    filename: file.name
                }
            });
            console.log(&#39;Upload to complete&#39;)
            return
        }

        let pool = []       // 并发池
        let max = 3         // 最大并发数
        let finish = 0      // 完成数量
        let failList = []   // 失败列表
        for(let i=0;i<list.length;i++){
            let item = list[i]
            let formData = new FormData()
            formData.append(&#39;filename&#39;, file.name)
            formData.append(&#39;hash&#39;, item.hash)
            formData.append(&#39;chunk&#39;, item.chunk)
            
            let task = axios({
                method: &#39;post&#39;,
                url: &#39;/upload&#39;,
                data: formData
            })

            task.then((data)=>{
                // 从并发池中移除已经完成的请求
                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)
}
Salin selepas log masuk

Pelaksanaan antara muka pelayan

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)
            const buffer = fs.readFileSync(chunk.path)
            const ws = fs.createWriteStream(`${dir}/${hash}`)
            ws.write(buffer)
            ws.close()
            res.send(`${filename}-${hash} Section uploaded successfully`)
        } catch (error) {
            console.error(error)
            res.status(500).send(`${filename}-${hash} Section uploading failed`)
        }
    })
})

//Merged slice interface
server.get('/merge', async (req, res) => {
    const { filename } = req.query
    try {
        let len = 0
        const bufferList = fs.readdirSync(`${STATIC_TEMPORARY}/${filename}`).map((hash,index) => {
            const buffer = fs.readFileSync(`${STATIC_TEMPORARY}/${filename}/${index}`)
            len += buffer.length
            return buffer
        });
        //Merge files
        const buffer = Buffer.concat(bufferList, len);
        const ws = fs.createWriteStream(`${STATIC_FILES}/${filename}`)
        ws.write(buffer);
        ws.close();
        res.send(`Section merge completed`);
    } catch (error) {
        console.error(error);
    }
})

server.listen(3000, _ => {
    console.log('http://localhost:3000/')
})
Salin selepas log masuk

Lagi Untuk berkaitan nod pengetahuan, sila lawati: tutorial nodejs!

Atas ialah kandungan terperinci Bagaimana untuk melaksanakan muat naik berbilang bahagian dalam Node.js? Pengenalan kaedah. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:segmentfault.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!