-
获取阿里云图片的过程
服务器返回图片地址——请求服务器返回图片真实地址——获取图片 -
目前遇到的问题
重复进行1的过程影响性能,实现图片加速加载。 -
在实际开发中的表现
·滑动列表时滑出去的item再次显示时会重复上述过程。
·反复查看某张图片。 -
实现过程
4.1 已经完成的实现
let params = {pics: paths, process: 'image/resize,m_fixed,w_76,h_76'};
// network是封装的联网请求
let result = await network({
type: "POST",
url: '/mobile/oss/signForAppPic',
param: params
}, token);
let reSetResult = result.response ? result.response : result;
let realPaths = reSetResult.result;
实现了在加载图片之前,从服务器获取真实的图片地址realPaths,然后再交给Image组件展示。发现真实的图片路径:https://gysy-picture.oss-cn-beijing.aliyuncs.com/app/x61tnmfx/BGQZ/ba112d3b-d41c-438a-ae88-002069a71aac.jpg?Expires=1543212261&OSSAccessKeyId=**********&Signature=*********&x-oss-process=image%2Fresize%2Cm_fixed%2Cw_100%2Ch_100
。
有一个参数Expires是该图片在阿里云失效的时间秒数。因此,出现了一个解决思路就是:缓存真实的图片地址,每次加载图片时先看是否有缓存,缓存的图片是否在有效期内,如果是就直接加载图片;否的话,获取图片真实地址,再加载图片并缓存。
4.2 实现步骤
-
图片地址的缓存,实现包括:初始化缓存对象、获取缓存中的值、设置缓存中的值。通过这几个方式实现了缓存的管理。(见4.3使用)
-
有效期的判断,通过Expires与当前时间的对比。在已实现代码前添加判断,添加后:
let realPaths;
if (isValid(cacheRealPaths) && this.state ) {
realPaths = cacheRealPaths;
return;
}
let params = {pics: paths, process: 'image/resize,m_fixed,w_76,h_76'};
// network是封装的联网请求,可以根据实际的联网请求进行更改
let result = await network({
type: "POST",
url: '/mobile/oss/signForAppPic',
param: params}, token);
let reSetResult = result.response ? result.response : result;
realPaths = reSetResult.result;
4.3 使用
将使用的方法封装到了ALiYunImageCache.js中。
/**
* 初始化缓存对象
* @param arr
* @returns {*}
*/
let initCache = (arr) => {
if (arr) {
return new Array(arr.length);
} else {
return null;
}
};
/**
* 获取缓存中的值
* @param arr
* @param index
* @returns {*}
*/
let getCache = (arr, index) => {
if (arr && arr.length > index) {
return arr[index];
} else {
return arr;
}
};
/**
* 设置缓存中的值
* @param arr
* @param index
* @param newItem
* @returns {*}
*/
let setCache = (arr, index, newItem) => {
if (arr && arr.length > index) {
return arr[index] = newItem;
} else {
return newItem;
}
};
/**
* 验证缓存是否有效
* @param cacheRealPaths
* @returns {boolean}
*/
let isValid = (cacheRealPaths) => {
if (cacheRealPaths && cacheRealPaths.length > 0) {
let start = cacheRealPaths[0].indexOf('=') + 1;
let end = cacheRealPaths[0].indexOf('&');
let validTime = parseInt(cacheRealPaths[0].substring(start, end));
let curTime = (new Date().getTime()) / 1000;
if (validTime > curTime) {
return true;
}
}
return false;
};
module.exports = {initCache, getCache, setCache, isValid};
- 初始化
构造方法里和缓存对象变化时,使用其中的initCache(arr)方法,返回保存的变量。arr:缓存的对象是列表时,传入对应的数组;否则传服务器返回的图片地址。 - 获取缓存对象
给展示图片的组件使用,getCache(arr, index)。arr是第一步保存的变量,index:缓存的对象是数组时,传入list中对应的索引;否则不传。 - 更新缓存
使用setCach(arr, index, newItem)。arr是第一步保存的变量,index:缓存的对象是数组时,传入list中对应的索引;否则传null。newItem:传新需要缓存的图片地址。
- 例子(一个列表每个item包含多张图片)
export default class demo extends Component {
constructor(props) {
super(props);
// 初始化
this.cacheRealPaths = initCache(props.connectListData);
}
componentWillReceiveProps(props) {
if (props.dataList !== this.props.dataList) {
// 所对应list数据变化时,重新初始化缓存
this.cacheRealPaths = initCache(props.dataList);
}
};
renderItem = ({item, index}) => (
<DemoItem
index={index}
data={item}
cacheRealPaths={getCache(this.cacheRealPaths, index)} // 获取该index对应的缓存
updateCacheRealPath={(index, arr) => setCache(this.cacheRealPaths, index, arr)} // 设置index对应的缓存
/>
);
render() {
return (
<View>
<FlatList
data={this.props.dataList}
keyExtractor={(item) => this.keyExtractor(item)}
renderItem={this.renderItem}
/>
</View>
);
}
}
class DemoItem extends Component {
render() {
return (
<View>
<PhotoHorizontalScroll
paths={this.props.data.pictures}
cacheRealPaths={this.props.cacheRealPaths}
updateCacheRealPath={(arr) => this.props.updateCacheRealPath(this.props.index, arr)}
</View>
)
}
}
export default class PhotoHorizontalScroll extends Component {
// 构造
constructor(props) {
super(props);
this.state = {
paths: []
};
...
this.newPaths = null;
}
...
showPictures = async (paths, cacheRealPaths) => {
this.newPaths = paths;
if (paths && paths.length > 0) {
// 添加有效判断
if (isValid(cacheRealPaths) && this.state ) {
this.setState({paths: cacheRealPaths});
return;
}
let userInfo = await getUserInfo();
let token = '';
if (userInfo) {
token = userInfo.access_token;
}
let params = {pics: paths, process: 'image/resize,m_fixed,w_76,h_76'};
let result = await network({
type: "POST",
url: '/mobile/oss/signForAppPic',
param: params
}, token);
let reSetResult = result.response ? result.response : result;
// 通知父组件更新缓存
this.props.updateCacheRealPath && this.props.updateCacheRealPath(reSetResult.result);
if (this.newPaths === paths && this.state) {
this.setState({
paths: reSetResult.result
})
}
}
else {
if (this.state) {
this.setState({
paths: []
})
}
}
};
...
render() {
return (
<ScrollView style={[this.props.style]}
horizontal={true}
showsHorizontalScrollIndicator={false}
>
<View style={{flexDirection: 'row'}}>
{this.renderImages(this.state.paths)}
</View>
</ScrollView>
);
}
}