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!
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
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>
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"); }
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: 'get', url: '/merge', params: { filename: file.name } }); console.log('Upload to complete') 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('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)=>{ // 从并发池中移除已经完成的请求 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) }
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/') })
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!