较多的图片(预计 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 10:57:43 +08:00 1
没有影响,放在内存速度只会更快。你硬件到位,内存随便用,但是你应该明白内存跟 磁盘的区别吧。
|
2
Eempty 2019-12-18 11:02:53 +08:00 1
现在的浏览器下,一般情况下没问题的,内存基本都够用
|
3
nvkou 2019-12-18 11:04:32 +08:00 via Android 1
好歹放 local storage 吧
|
4
neoblackcap 2019-12-18 11:23:59 +08:00 1
淘宝就是将很多图片放内存的,没有问题,前提是你的程序不会爆内存
|
5
noobma 2019-12-18 11:26:42 +08:00 1
window.performance.memory.jsHeapSizeLimit
应该足够你用的 |
6
Torpedo 2019-12-18 11:27:54 +08:00 1
这种应该不是直接存在了内存里吧。
就和你页面加载了 100 张图片,js 里肯定只是对这些资源的引用。 具体你通过 html 加载图片还是 js 都是一样的 |
7
7654 2019-12-18 11:29:00 +08:00 1
对于现在浏览器动辄几个 G 的内存占用,这点不算什么 doge
|
9
royzxq 2019-12-18 11:31:32 +08:00 1
首选考虑的应该是你需要多少时间来把这上 G 的图片加载进内存里。
|
10
xiaoming1992 OP @Foreverdxa 只是我不知道操作系统 /运行环境会不会对单个页面可用内存做限制,比方说虽然我手机内存 6G,但是手机只分配给微信 1G,微信只分配给单个 html 页面 100M,数值是随便说的,意思到位就行。
@nvkou 图片取用 /增删会很频繁,比方说 10 次 /s,这些图片说多不多,说少不少的,不太想放到 localStorage 里面,还得写兼容杂七杂八的,如果没大问题就直接放内存了,毕竟我看 three.js 也是直接保存在内存的 |
11
belin520 2019-12-18 11:38:39 +08:00 1
Chrome 单个 tab 有内存使用上限,不多的话,没有问题的。
|
12
xiaoming1992 OP |
13
zhw2590582 2019-12-18 11:39:18 +08:00 1
15M 不是事,我存视频数据到内存都是几个 G 的。
|
14
xiaoming1992 OP @royzxq 总共 10-15M,不是单张。。。
|
15
royzxq 2019-12-18 11:48:36 +08:00 1
@xiaoming1992 哦抱歉抱歉没看仔细,那才这么点大一点事情没有
|
16
xiangyuecn 2019-12-18 12:00:35 +08:00 1
看你#10 楼说的,这么大的时间间隙,最佳还是按需实时从网络加载更好些,全部缓存到内存是否有提前优化的嫌疑?
另外猜测意图并非同时需要显示大量图片,如果真需要全部缓存到内存时,尽量不要用 Image 对象来加载图片,自己写 xhr 请求得到二进制 ArrayBuffer,最多内存占用也就比 15M 多点,按需实时从内存实例化 Image 图片对象( onload 非常快)。直接用 Image 来进行缓存内存占用会翻个 10 几倍也是正常。 |
17
weixiangzhe 2019-12-18 12:14:04 +08:00 via Android 1
为什麽要保存在内存中呢,图片用 new image 加载一次回就有缓存了,之后直接用 src 就好了
|
18
xiaoming1992 OP @xiangyuecn 业务需求实际是同一时刻只有 3-7 张图片,然而需要根据鼠标动作频繁切换这几张图片的 src,再讲细一点就是比较特殊的环物展示。我还没想过直接处理 buffer,回去考虑一下,谢谢。
|
19
xiaoming1992 OP @weixiangzhe 其实本来就是利用的浏览器的缓存,或许是我描述有误
|
20
maichael 2019-12-18 12:32:43 +08:00 1
实测一下不就知道了。
|
21
lamada 2019-12-18 12:38:27 +08:00 1
缓存一般没有问题,楼上说的爆内存和这个关系应该不大。移动端图片爆内存的情况是一般是图片尺寸的原因,和文件大小无关。你可以计算所有展示的图片 w*h*4 来估算一下渲染时所占用的内存。
|
22
xiaoming1992 OP @lamada 我之前用过同时显示 8 张 4096*2048 的图片,手机动不动就黑屏……现在仅仅是 3-6 张 2000*1000,这么算的话大概百来 M,应该问题不大。
|
23
xiaoming1992 OP @maichael 设备太多了,没法一一测试啊,就怕内存占用处在临界点,这台设备好用,那台设备崩了,或者由于不同设备的缓存策略不同,缓存太多,如果动不动给我自动清掉一些缓存,也很烦啊。
|
24
weixiangzhe 2019-12-18 14:41:21 +08:00 via Android 1
图片太大结合 oss 的图片处理用,可以压缩为 webp 的格式 再控制下长宽就会好很多
|
25
mxT52CRuqR6o5 2019-12-18 14:43:22 +08:00 via Android 1
没啥问题,渲染出来的图片才会影响性能
|
26
xiaoming1992 OP @weixiangzhe 大小不能压缩,还要支持放大了看也清楚,已经压缩的足够了,2000*1000 的图片现在已经 100k 不到了
|
27
ofblyt 2019-12-18 14:52:17 +08:00 1
display:none 的图片好像也可以用在 canvas 里面,所以其实加几个隐藏的 div 加载图片就行
|
28
mxT52CRuqR6o5 2019-12-18 14:55:35 +08:00 via Android 1
@mxT52CRuqR6o5 不过楼主这种增加抽象复杂度的随取随用也没啥用,随便找个预加载库就是了
|
29
xiaoming1992 OP @mxT52CRuqR6o5 不太清楚"增加抽象复杂度"是什么意思,是说我这么搞让问题更复杂了嘛?
|
30
mxT52CRuqR6o5 2019-12-18 15:01:48 +08:00 via Android 1
@xiaoming1992 比如常规方法是通过图片 url 现场 new Image 插入网页,哪个 Image 是哪个 url 对应关系都很清楚,你先把所有的 Image 预生成再存到一个数组里,(别人接手项目)可能就不能马上理清每个 Image 对应哪个图片
|
31
xiaoming1992 OP @mxT52CRuqR6o5 由于我这边时不时需要操作这一组有序的图片,这一组 url 将会按照一定的规律画到同一个 canvas 上,所以才将他们放在一个数组里面的。。。
|
32
CODEWEA 2019-12-18 15:09:31 +08:00 1
道理我都懂,可是你这个就顶多是个图片懒加载啊,你如何证明是保存到 js 了?
|
33
mxT52CRuqR6o5 2019-12-18 15:12:43 +08:00 via Android 1
@xiaoming1992 url 现场生成 image 再画到 canvas 上,中间的步骤可以当做黑箱不用去太关心,更符合直觉
|
34
mxT52CRuqR6o5 2019-12-18 15:16:54 +08:00 via Android 1
@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 15:32:18 +08:00 via Android 1
@xiaoming1992 随便找个预加载的库就是了
|
39
xiangyuecn 2019-12-18 15:39:40 +08:00 1
@xiaoming1992 #36 URL.createObjectURL(blob)
|
40
xiaoming1992 OP @mxT52CRuqR6o5 我好像确实忘了去找库了,其实我一直纠结的是,浏览器会不会把我预加载的东西给清理掉
|
41
Mutoo 2019-12-18 15:46:26 +08:00 1
游戏引擎就是这么做的,没什么问题。
|
42
jsq2627 2019-12-18 19:29:33 +08:00 2
https://codepen.io/jsq2627/pen/ZEYLyEW?editors=1010
不做分片加载的话,那就有很大概率内存占用超出上限,页面崩溃。特别是低端安卓机。 如果你能手动控制好分片加载的话,那自然是 ok 的。 另外存 blob 和存 Image 有个区别是,blob 占用的是 JS heap 内存,最大上限比存 Image 小很多。 |
43
xiaojie668329 2019-12-18 21:30:07 +08:00 via iPhone 1
100 张肯定没问题,我试过存过千张几百 kb 的。
|
44
baihaihui 2019-12-18 21:59:45 +08:00 1
根据实现,图片不一定在内存。具体是 from disk cache 还是 from memory cahe 应该是分情况的
|
45
xiangyuecn 2019-12-18 23:21:18 +08:00 2
@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 00:14:00 +08:00
@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 11:44:42 +08:00
new Image 然后设置 src 不就行了
让浏览器自己管理 cache 不好吗,hack 除了好玩到底有啥优势 |
49
baihaihui 2019-12-19 13:16:30 +08:00
@xiaoming1992 浏览器是否清除缓存取决与缓存是如何配置的。有强缓存,协商缓存。对于图片直接配置成强缓存就行。如果内存使用过高,浏览器会自动落盘( from disk cache )。
|
50
muzuiget 2019-12-19 15:00:03 +08:00
楼主想多了,这种情况让浏览器自己优化就好了。说不定图片不可见,浏览器自己会把图片内存交换到硬盘上去呢。
|
51
xcstream 2019-12-19 15:12:35 +08:00
直接引用地址浏览器自动缓存的。
|
52
xiaoming1992 OP @KuroNekoFan 仅仅是 new image src,浏览器很快就会清掉缓存,所以才把他们存数组里的。
|
53
KuroNekoFan 2019-12-19 20:31:35 +08:00 via iPhone
@xiaoming1992 浏览器缓存是被 http header 控制的,请补充相关知识……
|