news 2026/8/6 15:26:48

URL.createObjectURL()、URL.revokeObjectURL() 详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
URL.createObjectURL()、URL.revokeObjectURL() 详解

URL.createObjectURL()详解


基本概念

URL.createObjectURL()是一个静态方法,用于为 Blob 或 File 对象创建一个唯一的 URL。这个 URL 可以在浏览器中像普通 URL 一样使用,但指向的是内存中的对象。


基本语法

javascript

const objectURL = URL.createObjectURL(object);

参数

  • object:File、Blob 或 MediaSource 对象

  • 返回值:一个字符串格式的 URL,格式为blob:origin/uuid

示例

javascript

// 为文本 Blob 创建 URL const textBlob = new Blob(['Hello, World!'], { type: 'text/plain' }); const blobURL = URL.createObjectURL(textBlob); console.log(blobURL); // blob:http://localhost:3000/550e8400-e29b-41d4-a716-446655440000

主要用途

1. 预览本地图片

javascript

// 图片预览功能 const input = document.getElementById('image-input'); const preview = document.getElementById('preview'); input.addEventListener('change', (e) => { const file = e.target.files[0]; if (file) { // 创建对象 URL const imageURL = URL.createObjectURL(file); // 显示预览 preview.src = imageURL; preview.style.display = 'block'; // 清理之前的 URL(如果有) if (preview.dataset.url) { URL.revokeObjectURL(preview.dataset.url); } // 保存当前 URL 引用 preview.dataset.url = imageURL; } }); // 页面卸载时清理 window.addEventListener('beforeunload', () => { if (preview.dataset.url) { URL.revokeObjectURL(preview.dataset.url); } });

2. 下载生成的内容

javascript

// 动态生成并下载文件 function downloadCSV(data, filename = 'data.csv') { // 创建 CSV 内容 const csvContent = data.map(row => row.map(cell => `"${cell}"`).join(',') ).join('\n'); // 创建 Blob const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); // 创建对象 URL const url = URL.createObjectURL(blob); // 创建下载链接 const link = document.createElement('a'); link.href = url; link.download = filename; link.style.display = 'none'; // 触发下载 document.body.appendChild(link); link.click(); document.body.removeChild(link); // 清理 URL setTimeout(() => URL.revokeObjectURL(url), 100); } // 使用示例 downloadCSV([ ['姓名', '年龄', '城市'], ['张三', '25', '北京'], ['李四', '30', '上海'] ]);

3. 视频/音频播放

javascript

// 播放录制的音视频 let mediaRecorder; let recordedChunks = []; // 开始录制 async function startRecording() { const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); mediaRecorder = new MediaRecorder(stream); mediaRecorder.ondataavailable = (event) => { if (event.data.size > 0) { recordedChunks.push(event.data); } }; mediaRecorder.start(); } // 停止并播放录制内容 function stopAndPlayRecording() { mediaRecorder.stop(); mediaRecorder.onstop = () => { // 创建包含录制数据的 Blob const blob = new Blob(recordedChunks, { type: 'video/webm' }); // 创建对象 URL const videoURL = URL.createObjectURL(blob); // 播放视频 const video = document.getElementById('player'); video.src = videoURL; video.controls = true; video.play(); // 清理旧的 URL if (video.dataset.url) { URL.revokeObjectURL(video.dataset.url); } video.dataset.url = videoURL; recordedChunks = []; }; }

4. 创建 Web Worker

javascript

// 动态创建 Worker function createInlineWorker(workerScript) { const blob = new Blob([workerScript], { type: 'application/javascript' }); const workerURL = URL.createObjectURL(blob); const worker = new Worker(workerURL); // 立即释放 URL(Worker 已加载) URL.revokeObjectURL(workerURL); return worker; } // 使用 const worker = createInlineWorker(` self.onmessage = function(e) { const result = e.data * 2; postMessage(result); }; `); worker.onmessage = (e) => console.log('结果:', e.data); worker.postMessage(42); // 输出: 结果: 84

技术细节

URL 的生命周期

javascript

const blob = new Blob(['data']); const url = URL.createObjectURL(blob); // 此时: // 1. 浏览器为这个 Blob 创建一个内部引用 // 2. 生成一个唯一的 URL // 3. 这个 URL 在文档卸载前有效,除非手动释放 // 使用后需要释放 URL.revokeObjectURL(url); // 释放后: // 1. URL 立即失效 // 2. 如果 Blob 没有其他引用,会被垃圾回收 // 3. 再次访问该 URL 会导致 404 错误

性能优化技巧

批量处理文件预览

javascript

class ImagePreviewManager { constructor() { this.urls = new Set(); } createPreview(files) { // 清理之前的预览 this.cleanup(); const previews = []; for (const file of files) { if (file.type.startsWith('image/')) { const url = URL.createObjectURL(file); this.urls.add(url); previews.push({ file, url, element: this.createImageElement(url) }); } } return previews; } createImageElement(url) { const img = new Image(); img.src = url; return img; } cleanup() { // 释放所有 URL for (const url of this.urls) { URL.revokeObjectURL(url); } this.urls.clear(); } } // 使用 const manager = new ImagePreviewManager(); document.getElementById('upload').addEventListener('change', (e) => { const previews = manager.createPreview(Array.from(e.target.files)); // 显示预览... }); // 页面离开时清理 window.addEventListener('beforeunload', () => manager.cleanup());

懒加载和缓存

javascript

const blobCache = new Map(); function getCachedBlobURL(content, type = 'text/plain') { const key = `${type}:${content}`; if (!blobCache.has(key)) { const blob = new Blob([content], { type }); const url = URL.createObjectURL(blob); blobCache.set(key, { url, timestamp: Date.now(), refCount: 0 }); // 定期清理缓存(30秒) setTimeout(() => { const cached = blobCache.get(key); if (cached && cached.refCount === 0) { URL.revokeObjectURL(cached.url); blobCache.delete(key); } }, 30000); } const cached = blobCache.get(key); cached.refCount++; return { url: cached.url, release: () => { cached.refCount--; } }; }

常见问题与解决方案

问题1:内存泄漏

javascript

// 错误示例:每次都创建新 URL 但不释放 function createDownloadLink(content) { const blob = new Blob([content]); const url = URL.createObjectURL(blob); // 每次都创建 const link = document.createElement('a'); link.href = url; // 忘记释放 URL! } // 正确示例 function createDownloadLink(content) { const blob = new Blob([content]); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = 'file.txt'; // 点击后清理 link.onclick = () => { setTimeout(() => URL.revokeObjectURL(url), 100); }; return link; }

问题2:URL 在 iframe 中的使用

javascript

// 在 iframe 中显示生成的 PDF function showPDFInIframe(pdfData) { const blob = new Blob([pdfData], { type: 'application/pdf' }); const url = URL.createObjectURL(blob); const iframe = document.createElement('iframe'); iframe.src = url; document.body.appendChild(iframe); // iframe 卸载时清理 iframe.addEventListener('load', () => { // PDF 已加载,可以释放 URL URL.revokeObjectURL(url); }); }

问题3:与 Service Worker 配合

javascript

// Service Worker 中缓存 Blob // 主线程 const blob = new Blob([data]); const url = URL.createObjectURL(blob); fetch(url) .then(response => response.blob()) .then(blobData => { // 缓存到 Service Worker caches.open('my-cache').then(cache => { cache.put('/cached-data', new Response(blobData)); }); // 释放 URL URL.revokeObjectURL(url); });

浏览器兼容性

支持情况

  • Chrome 8+

  • Firefox 4+

  • Safari 6+

  • Edge 12+

  • IE 10+


特性检测

javascript

if (window.URL && window.URL.createObjectURL) { // 支持 const url = URL.createObjectURL(blob); } else { // 降级方案:使用 FileReader const reader = new FileReader(); reader.onload = (e) => { const dataUrl = e.target.result; // data: URL // 使用 data URL }; reader.readAsDataURL(blob); }

最佳实践总结

  1. 及时释放:使用后立即调用revokeObjectURL()

  2. 错误处理:在 try-catch-finally 中确保释放

  3. 引用计数:复杂场景使用引用计数管理

  4. 作用域控制:将 URL 限制在最小作用域内

  5. 监控工具:使用浏览器开发者工具监控内存使用

javascript

// 最佳实践封装 function withObjectURL(blob, callback) { const url = URL.createObjectURL(blob); try { return callback(url); } finally { // 确保无论成功失败都释放 URL.revokeObjectURL(url); } } // 使用 const result = withObjectURL( new Blob(['data']), (url) => { // 在这里使用 url const img = new Image(); img.src = url; return img; } );

URL.createObjectURL()是现代 Web 开发中非常强大的工具,正确使用可以显著提升用户体验,但需要谨慎管理内存。


URL.revokeObjectURL()详解


基本概念

URL.revokeObjectURL()用于释放通过URL.createObjectURL()创建的对象 URL。这是内存管理的重要步骤。


基本用法

javascript

// 创建对象 URL const blob = new Blob(['Hello World'], { type: 'text/plain' }); const blobURL = URL.createObjectURL(blob); // 使用对象 URL const link = document.createElement('a'); link.href = blobURL; link.download = 'hello.txt'; // 使用完毕后释放 URL.revokeObjectURL(blobURL);

在 Web Worker 中的应用

正确的工作流程

javascript

// 1. 创建 Worker 脚本 const workerScript = `self.onmessage=({data})=>{console.log(data)};`; const workerScriptBlob = new Blob([workerScript]); const workerScriptBlobURL = URL.createObjectURL(workerScriptBlob); // 2. 创建 Worker const worker = new Worker(workerScriptBlobURL); // 3. Worker 创建后立即释放 URL(不会影响已创建的 Worker) URL.revokeObjectURL(workerScriptBlobURL); // 4. 使用 Worker worker.postMessage('Hello Worker'); // 5. 不再需要时终止 Worker worker.terminate();

为什么需要revokeObjectURL()

1. 内存管理

javascript

// 如果不释放,每次调用都会创建新的 URL,导致内存泄漏 function createWorkerLeaky(script) { const blob = new Blob([script]); const url = URL.createObjectURL(blob); // 每次调用都创建新 URL const worker = new Worker(url); // 忘记释放:URL 会一直占用内存 return worker; } // 正确版本 function createWorker(script) { const blob = new Blob([script]); const url = URL.createObjectURL(blob); const worker = new Worker(url); URL.revokeObjectURL(url); // 立即释放 return worker; }

2. 安全考虑

释放 URL 可以防止其他代码误用或访问已被删除的 Blob 内容。


关键特性

立即释放不影响已创建的对象

javascript

const blob = new Blob(['content']); const url = URL.createObjectURL(blob); // 创建 Worker 或下载链接 const worker = new Worker(url); const link = document.createElement('a'); link.href = url; // 立即释放 URL URL.revokeObjectURL(url); // 以下仍然有效: worker.postMessage('test'); // Worker 正常工作 link.click(); // 下载仍然进行 // 但这些会失败: const img = new Image(); img.src = url; // 错误:URL 已被撤销

生命周期示例

javascript

class WorkerManager { constructor() { this.workers = new Map(); // 存储 worker 和对应的 URL } createWorker(script) { const blob = new Blob([script]); const url = URL.createObjectURL(blob); const worker = new Worker(url); // 存储引用以便后续清理 this.workers.set(worker, url); // 可以立即释放 URL URL.revokeObjectURL(url); return worker; } terminateWorker(worker) { if (this.workers.has(worker)) { worker.terminate(); this.workers.delete(worker); } } // 清理所有 Worker cleanup() { for (const [worker, url] of this.workers) { worker.terminate(); // URL 已经释放,无需再次调用 revokeObjectURL } this.workers.clear(); } }

与 Data URL 的对比

Blob URL 方式(需要清理)

javascript

// 需要主动管理内存 const url = URL.createObjectURL(blob); // ... 使用 ... URL.revokeObjectURL(url); // 必须调用

Data URL 方式(自动管理)

javascript

// 自动垃圾回收,无需手动清理 const worker = new Worker(`data:application/javascript;base64,${btoa(script)}`); // 使用完毕后,GC 会自动回收

常见问题与解决方案

问题1:过早释放

javascript

// 错误:释放过早 const url = URL.createObjectURL(blob); URL.revokeObjectURL(url); // 立即释放 const worker = new Worker(url); // 错误:URL 已失效 // 正确:创建后再释放 const url = URL.createObjectURL(blob); const worker = new Worker(url); URL.revokeObjectURL(url); // Worker 创建后释放

问题2:重复释放

javascript

// 重复调用是安全的 const url = URL.createObjectURL(blob); URL.revokeObjectURL(url); URL.revokeObjectURL(url); // 安全,不会报错

问题3:异步操作中的释放

javascript

// 在异步操作中正确管理 URL async function processWithWorker(script, data) { const blob = new Blob([script]); const url = URL.createObjectURL(blob); try { const worker = new Worker(url); // 立即释放 URL,不影响 Worker URL.revokeObjectURL(url); return new Promise((resolve, reject) => { worker.onmessage = (e) => { worker.terminate(); resolve(e.data); }; worker.onerror = reject; worker.postMessage(data); }); } catch (error) { // 发生错误时也要释放 URL.revokeObjectURL(url); throw error; } }

最佳实践

  1. 立即释放原则:创建对象后立即释放 URL

  2. 错误处理:在 try-catch 中确保释放

  3. 避免全局变量:将 URL 存储在最小作用域中

  4. 使用封装函数

javascript

function createWorkerWithCleanup(script) { const blob = new Blob([script], { type: 'application/javascript' }); const url = URL.createObjectURL(blob); let worker; try { worker = new Worker(url); } finally { // 无论如何都释放 URL URL.revokeObjectURL(url); } return worker; } // 或者使用 IIFE 封装 const worker = (() => { const blob = new Blob([script]); const url = URL.createObjectURL(blob); const w = new Worker(url); URL.revokeObjectURL(url); return w; })();

浏览器兼容性

  • 现代浏览器完全支持

  • IE 10+ 支持

  • 移动端浏览器普遍支持


URL.revokeObjectURL()是 Web 开发中重要的内存管理工具,特别是在使用 Blob 和 File API 时。正确的使用可以避免内存泄漏,提升应用性能。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/5 17:04:31

冥想第一千七百三十五天(1735)

1.周二了,又是特别忙的一天,项目上全力以赴的一天,今天想换套餐但是1000m还到300m感觉不值得。 2.感谢父母,感谢朋友,感谢家人,感谢不断进步的自己。

作者头像 李华
网站建设 2026/8/4 17:14:39

代理IP和普通IP有什么区别?这篇文章帮你捋明白

在网络环境日益复杂的今天,代理IP成为企业与开发者频繁接触的关键词。但也有不少人常常疑惑:代理IP和普通IP究竟有什么不同?它们在使用场景、性能、安全性上又有何差异?本文将用通俗易懂的方式,从定义、功能、适用对象…

作者头像 李华
网站建设 2026/8/5 14:02:54

体系结构分类和指令系统

1.体系结构分类 1.1 按处理机的数量进行分类 按处理机的数量进行分类:单处理系统(一个处理单元和其他设备集成)、并行处理系统(两个以上的处理机互联)分布式处理系统(物理上远距离且松耦合的多计算机系统) 1.2 Flynn分类 分类有两个因素,即指令流和数据流&#…

作者头像 李华
网站建设 2026/8/5 19:15:40

基于AI数字人系统源码的低成本开发方案与实践经验

这两年,AI数字人从“概念展示”迅速走向商业落地。无论是企业官网数字客服、直播带货数字主播,还是教育、政务、金融等场景,AI数字人正在成为一种可复制、可规模化的新型生产力工具。但在实际交流中,我发现不少企业和开发者都会遇…

作者头像 李华
网站建设 2026/8/2 22:44:44

SQL 调优全解:从 20 秒到 200 ms 的 6 步实战笔记(附脚本)

一、阅读指引 1. 不会看执行计划 → 跳第 3 段 2. 索引失效/全表扫描 → 看第 4 段 3. 千万级分页卡顿 → 看第 5 段 4. 想直接抄代码 → 第 8 段有下载链接 二、测试环境 MySQL 8.0.34,16C64G,SSD;订单表 500w,明细表…

作者头像 李华
网站建设 2026/8/6 6:10:21

YOLO目标检测模型如何对接Apipost平台

前言 今天要给大家分享一个在工业巡检场景中非常实用的 AI 边缘计算部署实践。文中涉及的系统架构、接口设计和代码实现均为示例,主要用于说明整体思路和工程方法。我本人也是在实际项目中第一次系统性地接触边缘计算与算法接口化,很多经验都是在不断调…

作者头像 李华