以优先级

时间:2017-10-11 14:05:21

标签: reactjs redux axios

我目前正在开发反应应用程序以显示大量图像。

一开始,它不需要显示图像。 但是,在不久的将来可能需要一些图像。 首先使用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。这样,当相同的请求具有更高的优先级时,可以首先获取具有较高优先级的图像,或者可以较早地获取较低优先级的请求。

非常欢迎任何有关这种方法的意见。

感谢。

0 个答案:

没有答案