Firebase Storage用getDownloadURL,每次取URL还是下载到客户端一次更好?
关于Firebase计费的疑问解答
1. 直接给多个img赋值同一下载URL会不会重复计费?
不会。默认情况下,Firebase Storage返回的下载URL响应头会携带Cache-Control: public, max-age=3600配置,浏览器会自动缓存该资源1小时。同页面内多个img元素加载同一个URL时,只有第一次会真实发起网络请求到Firebase服务器,产生一次带宽计费,后续所有加载都会直接读取浏览器本地缓存,不会产生额外费用。
只有当缓存过期、用户主动清空浏览器缓存、或者你手动修改了Storage文件的Cache-Control配置为禁用缓存时,才会出现重复下载计费的情况。
2. 你提供的XHR下载转Blob URL的方案是否可行?
可行,这个方案确实可以保证资源仅下载一次,但是你的代码存在两处明显问题:
- 赋值逻辑的位置错误:你当前是在
xhr.send()之后直接给img赋值Blob URL,此时XHR请求还未完成,blob变量还是undefined,会直接报错,必须把赋值逻辑放到xhr.onload回调内部。 - 缺少内存释放逻辑:
URL.createObjectURL()生成的本地链接会一直占用内存,直到页面刷新,如果你页面会频繁更换头像,需要在头像不需要展示时调用URL.revokeObjectURL()主动释放资源,避免内存泄漏。
修正后的参考代码如下:
getDownloadURL(avatarRef).then(url => { const xhr = new XMLHttpRequest(); xhr.responseType = 'blob'; xhr.onload = (event) => { const blob = xhr.response; const localUrl = URL.createObjectURL(blob); // 遍历赋值用forEach更合适,map是用来生成新数组的API imgList.forEach(img => img.src = localUrl); }; xhr.open('GET', url); xhr.send(); })
更简单的替代方案
你不需要手动实现XHR下载逻辑,只要先创建一个临时Image对象预加载一次资源,后续给所有img赋值同一个远程URL即可,效果和Blob方案完全一致,代码更简洁:
getDownloadURL(avatarRef).then(url => { const preloadImg = new Image(); preloadImg.onload = () => { imgList.forEach(img => img.src = url); }; preloadImg.src = url; })
内容的提问来源于stack exchange,提问作者kr17
相关产品推荐
相关产品推荐

