
较多的图片(预计 100 张共计 10-15M )需要随取随用,我打算将他们保存在内存中,
const imgs: Image[] = [] 不知道会不会对程序的运行有什么不好的影响?比方说卡顿啊、图片内容丢失啊之类的?能推荐这方面(我也不知道哪方面...)的科普文就更好了。
有些同学对我说的“保存在内存”有疑问,直接上我的很简陋的方法
export function fetchImg(url: string) { return new Promise<HTMLImageElement>((resolve, reject) => { const img = new Image() function onload() { img.removeEventListener("load", onload) // eslint-disable-next-line @typescript-eslint/no-use-before-define img.removeEventListener("error", onerror) resolve(img) } function onerror(e: ErrorEvent) { img.removeEventListener("load", onload) img.removeEventListener("error", onerror) reject(e) } img.addEventListener("load", onload) img.addEventListener("error", onerror) img.src = url }) } 1 Foreverdxa 2019 年 12 月 18 日 没有影响,放在内存速度只会更快。你硬件到位,内存随便用,但是你应该明白内存跟 磁盘的区别吧。 |
2 Eempty 2019 年 12 月 18 日 现在的浏览器下,一般情况下没问题的,内存基本都够用 |
3 nvkou 2019 年 12 月 18 日 via Android 好歹放 local storage 吧 |
4 neoblackcap 2019 年 12 月 18 日 淘宝就是将很多图片放内存的,没有问题,前提是你的程序不会爆内存 |
5 noobma 2019 年 12 月 18 日 window.performance.memory.jsHeapSizeLimit 应该足够你用的 |
6 Torpedo 2019 年 12 月 18 日 这种应该不是直接存在了内存里吧。 就和你页面加载了 100 张图片,js 里肯定只是对这些资源的引用。 具体你通过 html 加载图片还是 js 都是一样的 |
7 7654 2019 年 12 月 18 日 对于现在浏览器动辄几个 G 的内存占用,这点不算什么 doge |
9 royzxq 2019 年 12 月 18 日 首选考虑的应该是你需要多少时间来把这上 G 的图片加载进内存里。 |
10 xiaoming1992 OP @Foreverdxa 只是我不知道操作系统 /运行环境会不会对单个页面可用内存做限制,比方说虽然我手机内存 6G,但是手机只分配给微信 1G,微信只分配给单个 html 页面 100M,数值是随便说的,意思到位就行。 @nvkou 图片取用 /增删会很频繁,比方说 10 次 /s,这些图片说多不多,说少不少的,不太想放到 localStorage 里面,还得写兼容杂七杂八的,如果没大问题就直接放内存了,毕竟我看 three.js 也是直接保存在内存的 |
11 icanfork 2019 年 12 月 18 日 Chrome 单个 tab 有内存使用上限,不多的话,没有问题的。 |
12 xiaoming1992 OP |
13 zhw2590582 2019 年 12 月 18 日 15M 不是事,我存视频数据到内存都是几个 G 的。 |
14 xiaoming1992 OP @royzxq 总共 10-15M,不是单张。。。 |
16 xiangyuecn 2019 年 12 月 18 日 看你#10 楼说的,这么大的时间间隙,最佳还是按需实时从网络加载更好些,全部缓存到内存是否有提前优化的嫌疑? 另外猜测意图并非同时需要显示大量图片,如果真需要全部缓存到内存时,尽量不要用 Image 对象来加载图片,自己写 xhr 请求得到二进制 ArrayBuffer,最多内存占用也就比 15M 多点,按需实时从内存实例化 Image 图片对象( onload 非常快)。直接用 Image 来进行缓存内存占用会翻个 10 几倍也是正常。 |
17 weixiangzhe 2019 年 12 月 18 日 via Android 为什麽要保存在内存中呢,图片用 new image 加载一次回就有缓存了,之后直接用 src 就好了 |
18 xiaoming1992 OP @xiangyuecn 业务需求实际是同一时刻只有 3-7 张图片,然而需要根据鼠标动作频繁切换这几张图片的 src,再讲细一点就是比较特殊的环物展示。我还没想过直接处理 buffer,回去考虑一下,谢谢。 |
19 xiaoming1992 OP @weixiangzhe 其实本来就是利用的浏览器的缓存,或许是我描述有误 |
20 maichael 2019 年 12 月 18 日 实测一下不就知道了。 |
21 lamada 2019 年 12 月 18 日 缓存一般没有问题,楼上说的爆内存和这个关系应该不大。移动端图片爆内存的情况是一般是图片尺寸的原因,和文件大小无关。你可以计算所有展示的图片 w*h*4 来估算一下渲染时所占用的内存。 |
22 xiaoming1992 OP @lamada 我之前用过同时显示 8 张 4096*2048 的图片,手机动不动就黑屏……现在仅仅是 3-6 张 2000*1000,这么算的话大概百来 M,应该问题不大。 |
23 xiaoming1992 OP @maichael 设备太多了,没法一一测试啊,就怕内存占用处在临界点,这台设备好用,那台设备崩了,或者由于不同设备的缓存策略不同,缓存太多,如果动不动给我自动清掉一些缓存,也很烦啊。 |
24 weixiangzhe 2019 年 12 月 18 日 via Android 图片太大结合 oss 的图片处理用,可以压缩为 webp 的格式 再控制下长宽就会好很多 |
25 mxT52CRuqR6o5 2019 年 12 月 18 日 via Android 没啥问题,渲染出来的图片才会影响性能 |
26 xiaoming1992 OP @weixiangzhe 大小不能压缩,还要支持放大了看也清楚,已经压缩的足够了,2000*1000 的图片现在已经 100k 不到了 |
27 ofblyt 2019 年 12 月 18 日 display:none 的图片好像也可以用在 canvas 里面,所以其实加几个隐藏的 div 加载图片就行 |
28 mxT52CRuqR6o5 2019 年 12 月 18 日 via Android @mxT52CRuqR6o5 不过楼主这种增加抽象复杂度的随取随用也没啥用,随便找个预加载库就是了 |
29 xiaoming1992 OP @mxT52CRuqR6o5 不太清楚"增加抽象复杂度"是什么意思,是说我这么搞让问题更复杂了嘛? |
30 mxT52CRuqR6o5 2019 年 12 月 18 日 via Android @xiaoming1992 比如常规方法是通过图片 url 现场 new Image 插入网页,哪个 Image 是哪个 url 对应关系都很清楚,你先把所有的 Image 预生成再存到一个数组里,(别人接手项目)可能就不能马上理清每个 Image 对应哪个图片 |
31 xiaoming1992 OP @mxT52CRuqR6o5 由于我这边时不时需要操作这一组有序的图片,这一组 url 将会按照一定的规律画到同一个 canvas 上,所以才将他们放在一个数组里面的。。。 |
32 CODEWEA 2019 年 12 月 18 日 道理我都懂,可是你这个就顶多是个图片懒加载啊,你如何证明是保存到 js 了? |
33 mxT52CRuqR6o5 2019 年 12 月 18 日 via Android @xiaoming1992 url 现场生成 image 再画到 canvas 上,中间的步骤可以当做黑箱不用去太关心,更符合直觉 |
34 mxT52CRuqR6o5 2019 年 12 月 18 日 via Android @mxT52CRuqR6o5 更符合直觉指的是我输入了一个 url,在 canvas 上就渲染了对应的图片 |
35 xiaoming1992 OP @mxT52CRuqR6o5 对,但是我必须预加载他,不能我需要了再临时加载,这是我做的一个小 demo https://m.lmoar.com/vrs/t/dist-example/example.html @CODEWEA 对,是图片预加载,如果仅仅 new Image.src = url,那么浏览器很快就会清掉缓存,我这边将返回的 img 保存到数组里面,**或许 /应该 /可能**浏览器不会清掉缓存。 |
36 xiaoming1992 OP @xiangyuecn 回来看了一下,ctx.drawImage 好像不能接受 blob 作为参数。。。 |
37 mxT52CRuqR6o5 2019 年 12 月 18 日 via Android @xiaoming1992 随便找个预加载的库就是了 |
39 xiangyuecn 2019 年 12 月 18 日 @xiaoming1992 #36 URL.createObjectURL(blob) |
40 xiaoming1992 OP @mxT52CRuqR6o5 我好像确实忘了去找库了,其实我一直纠结的是,浏览器会不会把我预加载的东西给清理掉 |
41 Mutoo 2019 年 12 月 18 日 游戏引擎就是这么做的,没什么问题。 |
42 jsq2627 2019 年 12 月 18 日 https://codepen.io/jsq2627/pen/ZEYLyEW?editors=1010 不做分片加载的话,那就有很大概率内存占用超出上限,页面崩溃。特别是低端安卓机。 如果你能手动控制好分片加载的话,那自然是 ok 的。 另外存 blob 和存 Image 有个区别是,blob 占用的是 JS heap 内存,最大上限比存 Image 小很多。 |
43 xiaojie668329 2019 年 12 月 18 日 via iPhone 100 张肯定没问题,我试过存过千张几百 kb 的。 |
44 baihaihui 2019 年 12 月 18 日 根据实现,图片不一定在内存。具体是 from disk cache 还是 from memory cahe 应该是分情况的 |
45 xiangyuecn 2019 年 12 月 18 日 @jsq2627 #42 这段代码有意思。我试了一个 200kb 的图片( 1800*1200 )加载 200 次的内存占用(约 50M 流量) 任务管理器里面报的内存,不知道是 windows 的是实际的还是 chrome 的是实际的,不过应该 600M+是有的,performance 里面的值雷打不动 刚开始加载并渲染 和 只加载不渲染 内存占用差不多( 50M 左右增量),然后我拖动页面让所有的图片都至少可见一次,内存立马爆炸到 600 多 M ;移除所有已显示的图片后,手动 GC 后内存正常回收。 看样子 Image 的性能优化的确实厉害,缓存了 Image 就没有必要用 Blob 了。 ------- 另外还测试了一下 2M 的 Blob *200 个,内存占用出现在浏览器的主进程( ID:8612 )上,并不在网页窗口的进程上;测试不断创建 1M 的 ArrayBuffer 就能把 chrome 主进程的内存占光(任务管理器里面看 2.4G 左右就不动了),然后内存放不下的 blob 疯狂写入硬盘( User Data\Default\blob_storage 目录),目测会把硬盘写满。测试代码( 12G 数据,机械盘估计更明显): ``` s=[];for(var i=0;i<12000;i++)s.push(new Blob([new Uint8Array(1*1024*1024)]));console.log("end") ``` |
46 xiaoming1992 OP @jsq2627 @baihaihui @xiangyuecn 这样说来,将图片直接用 image 缓存应该是可行的,不用做其他处理了吧。 梳理了一下自己的思路之后,发现我最初的疑问应当是,“浏览器是否会在一定的时候清理已缓存的图片”,经过初步测试,至少保存在数组中的 image 不会被清理。 |
47 jsq2627 2019 年 12 月 19 日 @xiangyuecn #45 看来我上面说的也不太对,blob 不占用 js heap,是有专门的存储系统来处理的 https://chromium.googlesource.com/chromium/src/+/master/storage/browser/blob/README.md @xiaoming1992 #46 应该只要注意内存量级就行。内存占用太多的话,低端设备会频繁触发 memory swapping,反而变成负优化 |
48 KuroNekoFan 2019 年 12 月 19 日 new Image 然后设置 src 不就行了 让浏览器自己管理 cache 不好吗,hack 除了好玩到底有啥优势 |
49 baihaihui 2019 年 12 月 19 日 @xiaoming1992 浏览器是否清除缓存取决与缓存是如何配置的。有强缓存,协商缓存。对于图片直接配置成强缓存就行。如果内存使用过高,浏览器会自动落盘( from disk cache )。 |
50 muzuiget 2019 年 12 月 19 日 楼主想多了,这种情况让浏览器自己优化就好了。说不定图片不可见,浏览器自己会把图片内存交换到硬盘上去呢。 |
51 xcstream 2019 年 12 月 19 日 直接引用地址浏览器自动缓存的。 |
52 xiaoming1992 OP @KuroNekoFan 仅仅是 new image src,浏览器很快就会清掉缓存,所以才把他们存数组里的。 |
53 KuroNekoFan 2019 年 12 月 19 日 via iPhone @xiaoming1992 浏览器缓存是被 http header 控制的,请补充相关知识…… |