前端 Blob 完全指南:从二进制处理到 10 + 实战场景,彻底搞懂 “二进制大对象” 的核心用法
前端 Blob 完全指南:从二进制处理到 10 + 实战场景,彻底搞懂 “二进制大对象” 的核心用法
Hello,我是叁佰万!提到 Blob(Binary Large Object,二进制大对象),很多前端开发者只知道它 “能处理二进制数据”,却不清楚它的实际价值 —— 其实 Blob 是前端操作二进制的 “基石”,从图片压缩、大文件上传,到离线缓存、PDF 生成,甚至视频处理,都离不开它的身影。今天就带大家从原理到实战,解锁 Blob 的 10+ 实用场景,让你真正会用、用活 Blob!
关注我的主页:更多前端底层技术干货持续更新,记得点赞收藏哦~https://blog.csdn.net/m0_73589512?spm=1011.2682.3001.5343
https://blog.csdn.net/m0_73589512?spm=1011.2682.3001.5343

一、先搞懂:Blob 到底是什么?
1. 核心定义
Blob 是浏览器提供的二进制数据接口,本质是一个 “容器”,可以存储任意格式的二进制数据(图片、视频、音频、PDF、zip 等),并提供了操作这些数据的基础方法(如切片、转换格式)。
2. Blob 与 File 的关系:“父类” 与 “子类”
很多人会混淆 Blob 和 File,其实两者是 “继承关系”:
-
File 对象是 Blob 的特殊类型,相当于 “增强版 Blob”;
-
除了拥有 Blob 的所有属性和方法,File 还额外添加了
name(文件名)、lastModified(最后修改时间)、lastModifiedDate(最后修改日期)等文件专属属性; -
简单说:所有 File 都是 Blob,但不是所有 Blob 都是 File。
比如通过 <input type="file"> 选择的文件,获取到的就是 File 对象,可直接当作 Blob 使用:
// 选择文件后,file 是 File 对象,也是 Blob 对象
const fileInput = document.querySelector('input[type="file"]');
fileInput.onchange = (e) => {
const file = e.target.files[0];
console.log(file instanceof Blob); // true
console.log(file.name); // 文件名(File 专属属性)
};
3. Blob 的核心属性与方法
(1)属性(只读)
-
size:Blob 数据的大小(以字节为单位); -
type:Blob 数据的 MIME 类型(如image/png、application/pdf),若无法识别则返回空字符串。
(2)核心方法
| 方法 | 作用 | 语法 |
|---|---|---|
slice() | 截取 Blob 的部分数据,返回新的 Blob 对象(大文件分片核心) | blob.slice(start[, end[, contentType]]) |
stream() | 将 Blob 转换为 ReadableStream(可逐块读取数据) | blob.stream() |
text() | 将 Blob 转换为字符串(默认 UTF-8 编码) | await blob.text() |
arrayBuffer() | 将 Blob 转换为 ArrayBuffer(操作底层二进制数据) | await blob.arrayBuffer() |
(3)常用工具方法(非 Blob 实例方法)
-
URL.createObjectURL(blob):生成 Blob 的临时 URL(如blob:http://xxx),可用于下载、预览; -
URL.revokeObjectURL(url):释放临时 URL(避免内存泄漏,必须手动调用); -
new Blob(array, options):创建新的 Blob 对象(array 是二进制数据数组,options 可指定type)。
二、10+ 实战场景:Blob 真正的实用价值
场景 1:图片压缩(最经典用法)
核心逻辑:通过 Canvas 压缩图片像素 / 质量,再用 toBlob() 转换为 Blob 对象,最后上传或下载。
完整代码:
/**
* 图片压缩函数
* @param {File} file - 原始图片文件(File/Blob 对象)
* @param {number} quality - 压缩质量(0-1,越小质量越低)
* @returns {Promise<Blob>} 压缩后的 Blob 对象
*/
function compressImage(file, quality = 0.7) {
return new Promise((resolve) => {
const img = new Image();
// 允许跨域图片(若图片来自CDN,需服务器配置CORS)
img.crossOrigin = 'anonymous';
// 用临时 URL 加载图片
img.src = URL.createObjectURL(file);
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 1. 缩小图片尺寸(按比例压缩,避免变形)
const maxWidth = 1920; // 最大宽度限制
let width = img.width;
let height = img.height;
if (width > maxWidth) {
height = Math.round((height * maxWidth) / width);
width = maxWidth;
}
canvas.width = width;
canvas.height = height;
// 2. 绘制图片(清除锯齿)
ctx.clearRect(0, 0, width, height);
ctx.drawImage(img, 0, 0, width, height);
// 3. 转换为 Blob(toBlob 是 Canvas 方法,直接输出 Blob)
canvas.toBlob(
(blob) => {
// 释放临时 URL,避免内存泄漏
URL.revokeObjectURL(img.src);
resolve(blob);
},
file.type || 'image/jpeg', // 保持原格式,默认 jpeg
quality // 压缩质量
);
};
});
}
// 使用示例:压缩后上传
const fileInput = document.querySelector('input[type="file"]');
fileInput.onchange = async (e) => {
const file = e.target.files[0];
if (!file.type.startsWith('image/')) return alert('请选择图片文件');
const compressedBlob = await compressImage(file, 0.6);
console.log('压缩前大小:', (file.size / 1024 / 1024).toFixed(2) + 'MB');
console.log('压缩后大小:', (compressedBlob.size / 1024 / 1024).toFixed(2) + 'MB');
// 上传到服务器(FormData 可直接接收 Blob)
const formData = new FormData();
formData.append('file', compressedBlob, 'compressed-' + file.name);
const res = await fetch('/api/upload', {
method: 'POST',
body: formData,
});
};
应用场景:
-
头像上传、图片分享(减少服务器存储和带宽消耗);
-
移动端拍照后压缩(手机拍照的图片通常几 MB 甚至几十 MB,压缩后更易上传)。
场景 2:大文件分片上传(解决大文件上传超时 / 失败)
核心逻辑:用 Blob.slice() 将大文件分割成多个小 Blob(分片),逐个上传,最后由服务器合并。
完整代码:
/**
* 大文件分片上传
* @param {File} file - 待上传文件
* @param {number} chunkSize - 分片大小(默认 5MB)
* @returns {Promise<void>}
*/
async function uploadLargeFile(file, chunkSize = 5 * 1024 * 1024) {
const fileSize = file.size;
const totalChunks = Math.ceil(fileSize / chunkSize); // 总分片数
const fileId = Date.now() + '-' + file.name; // 唯一标识(用于服务器合并)
for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
// 1. 截取分片(start:起始字节,end:结束字节)
const start = chunkIndex * chunkSize;
const end = Math.min(start + chunkSize, fileSize);
const chunkBlob = file.slice(start, end); // 核心:Blob.slice() 分片
// 2. 构造表单数据(包含分片信息)
const formData = new FormData();
formData.append('chunk', chunkBlob); // 分片 Blob
formData.append('fileId', fileId); // 文件唯一标识
formData.append('chunkIndex', chunkIndex); // 当前分片索引
formData.append('totalChunks', totalChunks); // 总分片数
formData.append('fileName', file.name); // 原文件名
// 3. 上传分片(可添加断点续传:记录已上传分片索引)
const res = await fetch('/api/upload-chunk', {
method: 'POST',
body: formData,
});
const result = await res.json();
if (!result.success) {
throw new Error(`分片 ${chunkIndex + 1} 上传失败`);
}
console.log(`分片 ${chunkIndex + 1}/${totalChunks} 上传成功`);
}
// 4. 所有分片上传完成,通知服务器合并
await fetch('/api/merge-chunk', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ fileId, fileName: file.name }),
});
console.log('文件上传完成!');
}
// 使用示例:上传 1GB 视频文件
const fileInput = document.querySelector('input[type="file"]');
fileInput.onchange = (e) => {
const file = e.target.files[0];
if (file.size > 1024 * 1024 * 1024) {
uploadLargeFile(file, 10 * 1024 * 1024); // 10MB 分片
}
};
进阶优化:
-
断点续传:上传前请求服务器,获取已上传的分片索引,跳过已上传部分;
-
并发上传:用 Promise.all 同时上传多个分片(控制并发数,避免服务器压力过大);
-
进度显示:通过
fetch的AbortController或XMLHttpRequest监听分片上传进度。
应用场景:
-
视频上传、大型压缩包上传、文档上传(单个文件几十 MB 以上)。
场景 3:生成临时下载链接(无需后端,前端直接下载文件)
核心逻辑:用 URL.createObjectURL(blob) 生成 Blob 的临时 URL,通过 <a> 标签触发下载。
示例 1:下载 JSON 数据为文件
/**
* 下载 JSON 数据为文件
* @param {object} data - JSON 数据
* @param {string} fileName - 下载文件名
*/
function downloadJsonAsFile(data, fileName = 'data.json') {
// 1. 将 JSON 转换为字符串
const jsonStr = JSON.stringify(data, null, 2);
// 2. 创建 Blob(指定 MIME 类型为 application/json)
const blob = new Blob([jsonStr], { type: 'application/json' });
// 3. 生成临时 URL
const url = URL.createObjectURL(blob);
// 4. 触发下载
const a = document.createElement('a');
a.href = url;
a.download = fileName; // 下载文件名
document.body.appendChild(a);
a.click();
// 5. 释放资源(关键:避免内存泄漏)
setTimeout(() => {
URL.revokeObjectURL(url);
document.body.removeChild(a);
}, 100);
}
// 使用示例:下载用户列表
const userList = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
];
downloadJsonAsFile(userList, '用户列表.json');
示例 2:下载 Canvas 绘制的图片
// Canvas 绘制完成后,直接下载
const canvas = document.querySelector('canvas');
const downloadBtn = document.querySelector('#downloadBtn');
downloadBtn.onclick = () => {
canvas.toBlob((blob) => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'canvas绘图.png';
a.click();
URL.revokeObjectURL(url);
});
};
应用场景:
-
导出表格数据为 CSV/JSON 文件;
-
下载前端生成的报告、图表(如 ECharts/Chart.js 绘制的图表);
-
下载 Canvas 绘图、用户编辑的图片。
场景 4:预览本地文件(图片 / 视频 / 音频 / PDF)
核心逻辑:用 URL.createObjectURL(blob) 生成临时 URL,赋值给 <img>、<video>、<audio>、<iframe> 等标签的 src 属性,实现本地预览(无需上传服务器)。
完整代码:
<!-- HTML -->
<input type="file" id="fileInput" accept="image/*,video/*,audio/*,application/pdf">
<div id="previewContainer"></div>
<script>
/**
* 预览本地文件
* @param {File} file - 本地文件
* @param {HTMLElement} container - 预览容器
*/
function previewFile(file, container) {
container.innerHTML = ''; // 清空之前的预览
const url = URL.createObjectURL(file);
// 根据文件类型创建对应的预览标签
switch (true) {
// 图片预览
case file.type.startsWith('image/'):
const img = document.createElement('img');
img.src = url;
img.style.maxWidth = '100%';
container.appendChild(img);
break;
// 视频预览
case file.type.startsWith('video/'):
const video = document.createElement('video');
video.src = url;
video.controls = true;
video.style.maxWidth = '100%';
container.appendChild(video);
break;
// 音频预览
case file.type.startsWith('audio/'):
const audio = document.createElement('audio');
audio.src = url;
audio.controls = true;
container.appendChild(audio);
break;
// PDF 预览(用 iframe)
case file.type === 'application/pdf':
const iframe = document.createElement('iframe');
iframe.src = url;
iframe.style.width = '100%';
iframe.style.height = '600px';
container.appendChild(iframe);
break;
default:
container.innerHTML = '不支持该文件类型预览';
}
// 页面卸载时释放 URL(避免内存泄漏)
window.addEventListener('unload', () => {
URL.revokeObjectURL(url);
});
}
// 绑定文件选择事件
document.querySelector('#fileInput').onchange = (e) => {
const file = e.target.files[0];
if (file) {
previewFile(file, document.querySelector('#previewContainer'));
}
};
</script>
应用场景:
-
上传文件前预览(如头像预览、视频预览);
-
本地文件管理器(前端实现简单的文件预览功能)。
场景 5:前端生成 PDF(结合 jsPDF 库)
核心逻辑:用 jsPDF 库生成 PDF 数据,再转换为 Blob 下载或上传。
步骤:
-
安装依赖:
npm install jspdf; -
生成 PDF 并转换为 Blob:
import jsPDF from 'jspdf';
/**
* 前端生成 PDF 并下载
*/
function generatePDF() {
// 1. 创建 PDF 实例(A4 纸,纵向,单位 mm)
const pdf = new jsPDF('portrait', 'mm', 'a4');
// 2. 向 PDF 中添加内容
pdf.text('前端 Blob 实战指南', 20, 20); // 文本(x, y 坐标)
pdf.text('作者:叁佰万', 20, 30);
pdf.addPage(); // 新增页面
pdf.text('场景 1:图片压缩', 20, 20);
pdf.text('场景 2:大文件分片上传', 20, 30);
// 3. 转换为 Blob(output 方法指定格式为 blob)
const pdfBlob = pdf.output('blob');
// 4. 下载 PDF
const url = URL.createObjectURL(pdfBlob);
const a = document.createElement('a');
a.href = url;
a.download = 'Blob实战指南.pdf';
a.click();
URL.revokeObjectURL(url);
// 可选:上传 PDF 到服务器
const formData = new FormData();
formData.append('pdf', pdfBlob, 'guide.pdf');
fetch('/api/upload-pdf', { method: 'POST', body: formData });
}
// 点击按钮生成 PDF
document.querySelector('#generatePdfBtn').onclick = generatePDF;
应用场景:
-
前端生成报表、合同、简历等 PDF 文件;
-
表单提交后,生成 PDF 回执并下载。
场景 6:离线资源缓存(结合 Service Worker + Cache API)
核心逻辑:用 Service Worker 拦截请求,将资源(如 JS、CSS、图片)转换为 Blob 存入 Cache API,实现离线访问。
关键代码(Service Worker 脚本):
// service-worker.js
const CACHE_NAME = 'blob-cache-v1';
const CACHE_RESOURCES = [
'/',
'/index.html',
'/static/js/main.js',
'/static/css/style.css',
'/static/images/logo.png',
];
// 安装 Service Worker 时缓存资源
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
// 缓存资源(将资源转换为 Blob 存入 Cache)
return cache.addAll(CACHE_RESOURCES);
}).then(() => self.skipWaiting())
);
});
// 激活 Service Worker 时清理旧缓存
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.filter((name) => name !== CACHE_NAME).map((name) => caches.delete(name))
);
}).then(() => self.clients.claim())
);
});
// 拦截请求,优先从缓存读取(离线可用)
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
// 缓存命中则返回缓存的 Blob 资源,否则请求网络
return response || fetch(event.request);
})
);
});
应用场景:
-
离线 Web 应用(如 PWA);
-
频繁访问的静态资源缓存(减少网络请求,提升加载速度)。
场景 7:处理后端返回的二进制流(如导出 Excel/PDF)
核心逻辑:后端返回二进制流数据(如 Excel 文件),前端用 response.blob() 转换为 Blob,再下载。
示例:下载后端生成的 Excel 文件
/**
* 下载后端返回的 Excel 文件
* @param {number} userId - 用户 ID(用于接口参数)
*/
async function downloadExcel(userId) {
try {
const res = await fetch(`/api/export-excel?userId=${userId}`, {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token'), // 携带令牌
},
});
if (!res.ok) throw new Error('下载失败');
// 1. 将响应转换为 Blob(指定 MIME 类型为 Excel)
const blob = await res.blob();
// 2. 从响应头获取文件名(后端需设置 Content-Disposition)
const disposition = res.headers.get('Content-Disposition');
const fileName = disposition
? disposition.split('filename=')[1].replace(/"/g, '')
: `用户${userId}数据.xlsx`;
// 3. 触发下载
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = fileName;
a.click();
URL.revokeObjectURL(url);
} catch (err) {
console.error('下载失败:', err);
}
}
// 使用示例:下载用户 1001 的 Excel 数据
downloadExcel(1001);
注意:
-
后端需设置响应头
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet(Excel 2007+ 格式); -
若需指定下载文件名,后端需设置
Content-Disposition: attachment; filename="用户数据.xlsx"。
应用场景:
-
导出后台数据为 Excel/PDF 文件(如订单数据、报表数据)。
场景 8:视频 / 音频切片处理(如流式播放)
核心逻辑:用 Blob.slice() 截取视频 / 音频的部分片段,实现 “按需加载” 或 “剪辑” 功能。
示例:截取视频片段并预览
/**
* 截取视频片段
* @param {File} videoFile - 原始视频文件
* @param {number} startSec - 开始时间(秒)
* @param {number} endSec - 结束时间(秒)
* @returns {Promise<Blob>} 截取后的视频 Blob
*/
function cutVideo(videoFile, startSec, endSec) {
return new Promise((resolve) => {
const video = document.createElement('video');
video.src = URL.createObjectURL(videoFile);
video.crossOrigin = 'anonymous';
video.onloadedmetadata = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const mediaRecorder = new MediaRecorder(video.captureStream());
const chunks = [];
// 设置画布尺寸与视频一致
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
// 开始录制
mediaRecorder.start();
// 跳转到开始时间
video.currentTime = startSec;
// 录制过程中收集 Blob 片段
mediaRecorder.ondataavailable = (e) => {
if (e.data.size > 0) chunks.push(e.data);
};
// 录制结束,合并为完整 Blob
mediaRecorder.onstop = () => {
const cutBlob = new Blob(chunks, { type: videoFile.type });
URL.revokeObjectURL(video.src);
resolve(cutBlob);
};
// 到达结束时间,停止录制
video.ontimeupdate = () => {
if (video.currentTime >= endSec) {
mediaRecorder.stop();
video.pause();
}
};
// 播放视频(触发录制)
video.play();
};
});
}
// 使用示例:截取视频前 10 秒
const fileInput = document.querySelector('input[type="file"][accept="video/*"]');
fileInput.onchange = async (e) => {
const videoFile = e.target.files[0];
const cutBlob = await cutVideo(videoFile, 0, 10);
// 预览截取后的视频
const video = document.createElement('video');
video.src = URL.createObjectURL(cutBlob);
video.controls = true;
document.body.appendChild(video);
};
应用场景:
-
视频剪辑工具(前端实现简单的视频片段截取);
-
流式播放(按需加载视频片段,减少带宽消耗)。
场景 9:结合 Web Assembly 处理大型二进制数据
核心逻辑:Web Assembly(Wasm)擅长处理计算密集型任务,Blob 可作为 Wasm 的数据输入 / 输出(如处理大型图片、解析二进制格式文件)。
简化示例:
// 假设已编译好 Wasm 模块(处理二进制数据的函数)
async function processBinaryWithWasm(blob) {
// 1. 将 Blob 转换为 ArrayBuffer(Wasm 可直接操作)
const arrayBuffer = await blob.arrayBuffer();
// 2. 加载 Wasm 模块
const wasmModule = await WebAssembly.instantiateStreaming(
fetch('/process-data.wasm')
);
// 3. 调用 Wasm 函数处理数据
const resultArrayBuffer = wasmModule.instance.exports.processData(arrayBuffer);
// 4. 将处理后的 ArrayBuffer 转换为 Blob(可下载或上传)
const resultBlob = new Blob([resultArrayBuffer], { type: 'application/octet-stream' });
return resultBlob;
}
// 使用示例:处理大型二进制文件
const fileInput = document.querySelector('input[type="file"]');
fileInput.onchange = async (e) => {
const blob = e.target.files[0];
const processedBlob = await processBinaryWithWasm(blob);
// 下载处理后的文件
const url = URL.createObjectURL(processedBlob);
const a = document.createElement('a');
a.href = url;
a.download = 'processed-file.bin';
a.click();
URL.revokeObjectURL(url);
};
应用场景:
-
大型图片处理(如人脸识别、图像滤镜);
-
解析特殊二进制格式文件(如自定义协议的数据包);
-
数据加密 / 解密(计算密集型加密算法用 Wasm 实现,Blob 传递数据)。
场景 10:前端解压 Zip 文件(结合 JSZip 库)
核心逻辑:用 JSZip 库读取 Zip 格式的 Blob,解压后获取内部文件。
步骤:
-
安装依赖:
npm install jszip; -
解压 Zip Blob:
import JSZip from 'jszip';
/**
* 前端解压 Zip 文件
* @param {Blob} zipBlob - Zip 格式的 Blob
*/
async function unzipFile(zipBlob) {
const zip = new JSZip();
// 1. 读取 Zip Blob
await zip.loadAsync(zipBlob);
// 2. 遍历 Zip 内的所有文件
const fileList = [];
for (const fileName of Object.keys(zip.files)) {
const file = zip.files[fileName];
if (!file.dir) { // 排除文件夹,只处理文件
// 3. 将文件内容转换为 Blob
const fileBlob = await file.async('blob');
fileList.push({
name: fileName,
blob: fileBlob,
size: fileBlob.size,
type: fileBlob.type,
});
}
}
// 4. 示例:预览解压后的图片文件
const previewContainer = document.querySelector('#previewContainer');
fileList.forEach((file) => {
if (file.type.startsWith('image/')) {
const img = document.createElement('img');
img.src = URL.createObjectURL(file.blob);
img.style.maxWidth = '100px';
img.title = file.name;
previewContainer.appendChild(img);
}
});
return fileList;
}
// 使用示例:解压上传的 Zip 文件
const fileInput = document.querySelector('input[type="file"][accept=".zip"]');
fileInput.onchange = async (e) => {
const zipFile = e.target.files[0];
await unzipFile(zipFile);
};
应用场景:
-
前端解压用户上传的 Zip 包(如批量上传图片的压缩包);
-
离线应用中解压预下载的资源包。
三、Blob 使用的关键注意事项
-
释放临时 URL,避免内存泄漏:
-
用
URL.createObjectURL(blob)生成的 URL 会占用浏览器内存,使用后必须调用URL.revokeObjectURL(url)释放; -
建议在下载完成、预览结束或组件卸载时调用。
-
-
MIME 类型正确设置:
-
创建 Blob 时,指定正确的
type(MIME 类型),否则可能导致文件无法正常打开(如application/json、image/png); -
常见 MIME 类型参考:图片(
image/*)、视频(video/*)、音频(audio/*)、PDF(application/pdf)、Excel(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)。
-
-
跨域资源处理:
-
若 Blob 数据来自跨域资源(如 CDN 图片),需确保服务器配置 CORS(
Access-Control-Allow-Origin),否则无法操作 Blob(如 Canvas 绘制、转换为 ArrayBuffer)。
-
-
大文件内存限制:
-
处理超大 Blob(如几十 GB 的文件)时,需注意浏览器内存限制,建议用分片(
slice())或流式(stream())处理,避免一次性加载整个文件到内存。
-
四、总结
Blob 作为前端二进制数据的 “基石”,其核心价值在于提供了统一的二进制处理接口,让前端能够脱离后端直接操作图片、视频、文件等二进制资源。从最基础的图片压缩、文件预览,到复杂的大文件分片上传、离线缓存、PDF 生成,Blob 贯穿了前端开发的多个核心场景。
掌握 Blob 的关键,不在于死记硬背属性和方法,而在于理解 “二进制数据容器” 的本质 —— 无论什么格式的二进制数据,都能通过 Blob 进行切片、转换、传输和存储。结合 Canvas、FormData、Service Worker、Wasm 等技术,还能解锁更多高级用法。
如果这篇文章帮你打开了 Blob 的 “新世界”,别忘了点赞、收藏、关注三连!后续还会分享更多前端底层技术、实战技巧,我们下期见~
更多推荐



所有评论(0)