假设我有一个网址列表,如下所示:
[ '/images/1', '/images/2', ... ]
我想预取n
这些,以便在图像之间转换更快。我现在在componentWillMount
做的事情如下:
componentWillMount() {
const { props } = this;
const { prefetchLimit = 1, document = dummyDocument, imgNodes } = props;
const { images } = document;
const toPrefecth = take(prefetchLimit, images);
const merged = zip(toPrefecth, imgNodes);
merged.forEach(([url, node]) => {
node.src = url;
});
}
imgNodes
的定义如下:
imgNodes: times(_ => new window.Image(), props.prefetchLimit),
和times
,zip
和take
。
现在当我在里面使用那些网址时反应如下:
<img src={url} />
无论网址在何处使用,它都会根据Etag
和Expire
标记点击浏览器缓存。每当我们点击视图内的n
时,我也会计划使用此功能预取下一个n - 1
图片,并以相同的方式重复使用imgNodes
。
我的问题是:
这是否是一个有效的想法,会给出100多个会使用这个想法的组件,但一次只能看到1个?
这样做会遇到内存问题吗?我假设在卸载组件时将imgNodes
进行垃圾回收。
我们正在使用redux
所以我可以将这些图像保存在商店中,但这似乎是我正在处理缓存而不是利用浏览器的自然缓存。
这个想法有多糟糕?
答案 0 :(得分:6)
您不需要在所有组件中执行此操作。一旦下载了图像,它就会被浏览器缓存,并且可以在所有组件中访问,因此您只能在高级组件中的某个位置执行此操作。
我不知道您试图通过缓存图片创建的UX究竟是什么,但是,您的代码只会启动下载图像,但不知道图像是否正在下载,是否已成功下载或甚至是失败。因此,例如,您想要显示一个按钮来更改图像或仅在下载图像时将类添加到组件(为了使图像平滑),您当前的代码可能会让您失望。
您可能希望使用Promises解决此问题。
// create an utility function somewhere
const checkImage = path =>
new Promise(resolve => {
const img = new Image()
img.onload = () => resolve(path)
img.onerror = () => reject()
img.src = path
})
...
// then in your component
class YourComponent extends Component {
this.state = { imagesLoaded: false }
componentDidMount = () =>
Promise.all(
R.take(limit, imgUrls).map(checkImage)
).then(() => this.setState(() => ({ imagesLoaded: true })),
() => console.error('could not load images'))
render = () =>
this.state.imagesLoaded
? <BeautifulComponent />
: <Skeleton />
}
关于记忆消耗 - 我不认为会发生任何不好的事情。浏览器通常会限制并行xhr请求的数量,因此您无法创建巨大的堆使用峰值以使任何事情崩溃,因为未使用的图像将被垃圾收集(但仍保留在浏览器缓存中)。
Redux商店是存储应用程序状态的地方,而不是应用程序资产,但无论如何您都无法在那里存储任何实际图像。