涉及远程请求大量图片,图片切换过程中的白屏现象

400 阅读2分钟

之前开发过程中遇到的问题。(由于购买的是外部接口,现在已经到期了,最近秋招在复盘项目中遇到的困难,所以没办法复现,拿出截图证明数据)

首先说一下需求吧

整体是一个大屏项目,然后中间有地图使用的是LarkMap,我需要在地图上渲染出云层流动的效果(这里用的是一个input框,滑动数值,通过定时器循环切换图片,达到云层流动快慢的效果)。

然后再清点一下所拥有的资源

两个接口(第三方购买的),第一个接口携带key用于请求所有图片的url,第二个接口利用第一个接口请求回来的url携带上第一个接口请求回来的key,请求图片资源。

首次做法

通过嵌套接口调用,请求回来云层图片的url,将云层图片的url数组,通过useState存到状态中,然后通过一个函数循环请求图片,将请求结果渲染到页面上。

目前遇到的问题

通过两个接口嵌套,每张图片都通过网络请求获取,然后记忆中每张图片平均请求时间是173ms,而且不包含将图片渲染到屏幕的时间,这样导致的问题就是:云层图片切换,每次切换之前都要发送请求,然后再渲染到屏幕上,这样就会导致中间有空白期,肉眼可见的白屏。

解决思路

主要就是解决请求缓慢的问题。于是想到能否请求图片实体,将图片实体缓存到本地,每次从实体取出。

上代码:

通过async/await和Promise.all()异步请求所有图片资源,将图片资源转成blob对象,存进currentImage状态中。

  const asyncFetch = async () => {
    try {
      const response = await fetch(
        'https://something.com/v4?fields=precip_minutely_fcst_map&key=xxxxxxx',
      );
      const json = await response.json();

      const images = [];
      const times = [];

      await Promise.all(
        json.precip_minutely_fcst_map[0].data.slice(0, 23).map(async (item) => {
          const imageUrl = `${item.url}?key=xxxxxxx`;
          times.push(item.time);
          const res = await fetch(imageUrl);
          const blob = await res.blob();
          images.push(blob);
        }),
      );

      setCurrentImage(images);
      setTimes(times);
    } catch (error) {
      console.error('请求出错了', error);
    }
  };

由于larkmap图片图层暂时支持的数据源只能是图片的url,所以还需要将blob对象转成本地url

  const updateImage = () => {
     //设置当前图层所对应的时间
    const timeString = new Date(Times[index]).toLocaleTimeString([], {
      hour: '2-digit',
      minute: '2-digit',
      second: '2-digit',
    });
    // 清理之前的 URL(避免内存泄漏) 
    if (rainSource && rainSource.data) { 
       window.URL.revokeObjectURL(rainSource.data); 
    }
    
    let imageUrl = currentImage[index];
    // 将 Blob 对象转换为可用于显示的 URL
    let imgUrl = window.URL.createObjectURL(new Blob([imageUrl]));

    // 更新 rainSource
    setRainSource({
      data: imgUrl,
      parser: {
        type: 'image',
        extent: [63.8148899733, 12.7700338517, 143.536486117, 56.3833398551],
      },
    });

    setCurrentImageTime(timeString);
    setIndex((index + 1) % 23);
  };

结果

从本地取出的图片平均耗时为4ms(之前本地缓存没消失,还能返回304),白屏问题的到解决了。 image.png