我目前正在开发反应应用程序以显示大量图像。
一开始,它不需要显示图像。 但是,在不久的将来可能需要一些图像。 首先使用redux,axios和mongodb请求这些图像。
但是,由于仍然有很多请求,它会冻结整个应用程序。
我想知道是否有办法处理这个问题,以便在不损害整体性能的情况下请求候选图像(可能作为后台任务或优先级)。
EDIT。
这些图像是从renderBin反应类中请求的。它根据其道具中的类型呈现svg形状或图像。它通常首先渲染一个形状,然后根据用户交互变成一个图像。请注意,有一个上层类调用多个来在svg上呈现多个bin。我想在实际获得用户交互之前获取图像并显示这些图像。
class RenderBin extends React.Component {
constructor(){
super();
this.state = {
id: _.uniqueId('bin_'),
src: null,
srcUrl: null
};
}
componentDidMount() {
const {imagePool, getThumbnails, src} = this.props;
if (imagePool[src]) {
this.setState({src: src, srcUrl: imagePool[src]});
return;
}
getThumbnails(src);
}
componentWillReceiveProps(nextProps) {
const {imagePool, src, getThumbnails} = nextProps;
const oldSrc = this.state.src;
if (oldSrc === src) {
if (imagePool[src]) {
this.setState({src: src, srcUrl: imagePool[src]});
}
} else {
if (imagePool[src]) this.setState({src: src, srcUrl: imagePool[src]});
else getThumbnails(src);
}
}
renderCircle = (...) => {...}
renderRect = (...) => {...}
renderImage = (x,y,w,h) => {
return (
<image href={this.state.srcUrl} x={x} y={y} width={w} height={h}
);
}
render() {
switch(this.props.type) {
case 'rect': return this.renderRect(...);
case 'circ': return this.renderCirc(...);
case 'img': return this.renderImage(...);
}
}
}
在getThumnails函数中,它按如下方式请求图像。
export function getThumbnails(fn) {
return function(dispatch){
axios.get('/api/image/thumbnails/' + fn)
.then(function(response){
dispatch({
type: "GET_THUMBNAILS",
payload: {
name: fn,
url: '/api/image/thumbnails' + fn
}
})
})
.catch(function(err){
dispatch({
type: "GET_THUMBNAILS_REJECTED",
payload: err
})
});
};
}
在图像缩小器中,它按如下方式更新imagePool:
const INITIAL_STATE = {imagePool:{}};
function getThumbnails(state, payload){
const {name, url} = payload;
if (state.image[name] === undefined) {
const img = {[name]: url};
return {...state, imagePool: {...state.imagePool, ...img}};
}
return state;
}
export function imgReducers(state=INITIAL_STATE, action) {
const {type, payload} = action;
switch(type) {
case "GET_THUMBNAILS": return getThumbnails(state, payload);
default: return state;
}
}
编辑2(当前解决方案) 我可以稍微提高性能(至少到目前为止它还没有冻结应用程序)。
我的方法是有两个列表来存储已挂起和正在进行的请求。首先将获取图像的动作添加到存储所有图像请求的列表中(所谓的pendedRequest)。然后将其中一个挂起的请求推送到另一个列表,该列表存储所有正在进行的请求,即所谓的underRequest。请求完成后,将从underRequest列表中删除相应的项目。这实际上有助于避免重复请求。最后,我设置了两个配置参数以避免繁重的网络流量。一种是限制正在进行的请求的数量,另一种是设置触发动作(或请求)的延迟。修改后的代码如下。
import axios from 'axios';
import config from '../../config';
const pendedRequest = []; // a list of pended requests
const underRequest = []; // a list of on-going requests
export function getThumbnails(fn) {
return function(dispatch) {
axios.get('/api/image/thumbnails/' + fn)
.then(function(response){
// remove completed request from the underRequest list
let idx = underRequest.indexOf(fn);
if (idx > -1) underRequest.splice(idx,1);
// dispatch an action to update imagePool
... (same as above) ...
})
.catch(...(same as above)...);
};
}
// function used in RenderBin class
export function getThumbnailAsync(fn) {
return dispatch => {
// if it is on-going, discard the request
if (underRequest.indexOf(fn) > -1) return;
// if it is not in the pended requests, add the request
if (pendedRequest.indexOf(fn) === -1) pendedRequest.push(fn);
// if there are more than 'threshold' on-going actions,
// then will come later
if (underRequest.length > config.IMAGE_MAX_REQUEST) return;
// consumes one of requests in the pendedRequest
const pended = pendedRequest.shift();
underRequest.push(pended);
// delay the execution proportional to the length of on-going requests
// to avoid heavy network traffic
setTimeout(() => {
dispatch(getThumbnails(pended))
}, config.THUMBNAIL_TIMEOUT * underRequest.length);
};
}
我要修改一下,用优先级队列替换pendedRequest。这样,当相同的请求具有更高的优先级时,可以首先获取具有较高优先级的图像,或者可以较早地获取较低优先级的请求。
非常欢迎任何有关这种方法的意见。
感谢。