图片上传成功后,由后端生成缩略图,图片太多了缩略图任务在排队中,如何处理网页端加载图片这个过程呢?

上传多张图片后,缩略图由后端创建任务去生成。遇到问题就是,任务排队需要时间去等待,页面展示图片的缩略图怎么显示好呢?
目前我设置的是利用延时去加载一个loading的图片,先加载loading图片,3s后再去加载缩略图,缩略图加载失败则加载失败的图。
这样处理的问题就是,3s后任务还没有结束缩略图还未生成的话,就会显示加载失败的图片,用户会误以为缩略图生成失败。怎么解决这种问题呢?

interface IProps {
  onClick: () => void;
  src: any;
  source?: any; // 原图
  preThumb?: any;
  waitThumb?: boolean; // 是否等待加载缩略图
}
const ImageWithLoading = (props: IProps) => {
  const { onClick, source, waitThumb = false, preThumb } = props;
  const [imgSrc, setImgSrc] = useState<any>(loadingImg);
  const time: any = useRef();
  useEffect(() => {
    // 如果暂时没有图片显示,则延时去加载预上传的图片
    if (!props.src && waitThumb && preThumb) {
      time.current = setTimeout(() => {
        onPreLoad(preThumb, false);
      }, 3000);
    }
    return () => {
      clearTimeout(time.current);
    };
  }, [props.src]);
  const onPreLoad = (src: string, sourceSrc?: boolean) => {
    const img = new Image();
    img.onload = () => {
      setImgSrc(preThumb);
    };
    // 若图片加载失败则加载原图, 若加载原图都失败则显示错误图片
    img.onerror = () => {
      if (sourceSrc) {
        setImgSrc(errorImg);
      } else {
        onPreLoad(source, true);
      }
    };
    img.src = src;
  };
  const onLoad = () => {
    if (props.src) {
      const img = new Image();
      img.onload = () => {
        setImgSrc(props.src);
      };
      img.onerror = () => {
        setImgSrc(errorImg);
      };
      img.src = props.src;
    }
  };
  return (
    <>
      <img
        src={imgSrc}
        onLoad={onLoad}
        onClick={onClick}
        width="100%"
        style={{ maxHeight: '100%', objectFit: 'contain' }}
      />
    </>
  );
};

传图和页面展示是分开的两个页面,文件上传到minio上后返回的地址传到后端去生成的缩略图。
页面展示那里如果去读取图片的原图用FileRender生成缩略图的话,加载也比较慢。浏览器网速不行的话还是有限制的。

阅读 4.2k
4 个回答

现在缩略图的功能,不需要后端,纯前端就可以完成。

js中有一个FileReader的方法,可以读取通过input[type=file]文件上传控件上传的文件,不用等待后端接口的数据就能展示缩略图。

var upimg = document.querySelector('#upimg');
upimg.addEventListener('change', function (e) {
    var files = this.files;
    if (files.length) {
        // 对文件进行处理,下面会讲解checkFile()会做什么
        checkFile(this.files);
    }
});

// 图片处理
function checkFile(files) {
    var file = files[0];
    var reader = new FileReader();
    // show表示<div id='show'></div>,用来展示图片预览的
    if (!/image\/\w+/.test(file.type)) {
        show.innerHTML = '请确保文件为图像类型';
        return false;
    }
    // onload是异步操作
    reader.onload = function (e) {
        show.innerHTML = '<img src="' + e.target.result + '" alt="img">';
    };
    reader.readAsDataURL(file);
}

参考链接:html5实现图片预览和查看原图

任务排队需要时间去等待

可以使用Lambda函数

一个一个发给后端,你一次发好多,后端也吃内存跑不动啊。而且这样你前面可以做进度条,完成一个显示一个缩略图,用户也好知道正在处理。

已参与了 SegmentFault 思否社区 10 周年「问答」打卡 ,欢迎正在阅读的你也加入。

正常的设计逻辑是:后端在处理过程中保持会话,如果处理成功,则返回图片的 URL,如果失败,则返回约定的状态码,在会话开启期间,始终显示 Loading
当然,考虑到这个后端的处理效率堪忧(3sTimeout犹嫌不够),可以考虑让后端提供一个状态查询接口,轮询这个接口,检查图片是否加载成功,轮询期间显示 Loading后端必须给出任务的确切状态码:处理中、成功、失败,不能仅靠图片加载成功与否来判断,因为失败的加载隐含着处理中和处理失败两种状态,这就是你现在遇到的问题。

或者就直接在前端用Canvas处理缩略图。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题