Published on

分批加载图片列表——队列的使用

Authors

现在有个需求:从服务端获取到一个图片列表,为了增强用户体验,需要从前往后每3张分批加载图片,我们可以用队列的理念解决这个问题。什么是队列呢?维基百科对它的解释:

队列,又称为伫列(queue),计算机科学中的一种抽象资料类型,是先进先出(FIFO, First-In-First-Out)的线性表。在具体应用中通常用链表或者数组来实现。队列只允许在后端(称为rear)进行插入操作,在前端(称为front)进行删除操作。

我们可以把它理解成一个先进先出的数组,即首先把图片列表的1到3的图片放进数组,这3张图片加载完成后就把他们推出队列,然后把4到6的图片放进队列并加载,重复以上操作,直至在在玩所有图片。下面是实现代码:

const fetchImgList = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve([
        'https://cn.bing.com/th?id=OHR.GimignanoTuscany_ZH-CN8059318824_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
        'https://cn.bing.com/th?id=OHR.CorbettTigers_ZH-CN6927569938_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
        'https://cn.bing.com/th?id=OHR.BeachHutsSweden_ZH-CN4193150313_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
        'https://cn.bing.com/th?id=OHR.RhinelandVineyards_ZH-CN3332101688_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
        'https://cn.bing.com/th?id=OHR.PontNeuf_ZH-CN3158359446_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
        'https://cn.bing.com/th?id=OHR.SmokyMountainTrail_ZH-CN4691667074_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
        'https://cn.bing.com/th?id=OHR.SheepCousins_ZH-CN4262132476_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
        'https://cn.bing.com/th?id=OHR.MethoniCastle_ZH-CN4054146065_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
      ]);
    }, 500);
  });
};

// 首先请求接口拿到图片列表,然后分批放入队列请求图片
const list = await fetchImgList();
const queue = [];

for (let i = 0; i < list.length; i += 3) {
  queue.push(list.slice(i, i + 3)?.filter(item => !!item));
}

console.log(queue);

然后请求队列中的图片,请求完成后把图片链接推出队列,并把图片显示在页面上。

while (queue.length) do {
  try {
    // 加载队列中的图片,加载后把图片推出队列
  } catch (e) {

  }
}

完整代码如下:

const fetchImgList = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve([
        'https://cn.bing.com/th?id=OHR.GimignanoTuscany_ZH-CN8059318824_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
        'https://cn.bing.com/th?id=OHR.CorbettTigers_ZH-CN6927569938_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
        'https://cn.bing.com/th?id=OHR.BeachHutsSweden_ZH-CN4193150313_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
        'https://cn.bing.com/th?id=OHR.RhinelandVineyards_ZH-CN3332101688_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
        'https://cn.bing.com/th?id=OHR.PontNeuf_ZH-CN3158359446_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
        'https://cn.bing.com/th?id=OHR.SmokyMountainTrail_ZH-CN4691667074_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
        'https://cn.bing.com/th?id=OHR.SheepCousins_ZH-CN4262132476_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
        'https://cn.bing.com/th?id=OHR.MethoniCastle_ZH-CN4054146065_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
      ]);
    }, 500);
  });
};

const imgList = await fetchImgList();

const batchLoadImages = async (list, batchCount = 3) => {
  const loadImg = (imgSrc) => {
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.src = imgSrc;
      img.onload = () => {
        document.body.appendChild(img);
        resolve();
      }

      img.onerror = (e) => {
        reject(e.message);
      }
    })
  };
  const queue = [];

  // 分批放入队列
  for (let i = 0; i < list.length; i += batchCount) {
    queue.unshift(list.slice(i, i + batchCount)?.filter(item => !!item));
  }

  while (queue.length) {
    const requester = queue[queue.length - 1].map(item => loadImg(item));
    await Promise.all(requester);
    queue.pop();
  }
};

batchLoadImages(imgList);