如何在大页面上处理延迟加载图像?

时间:2016-07-20 14:39:39

标签: javascript html lazy-loading

我们用于延迟加载图片的当前方法是:

服务器端模板将所有图像元素呈现为:

<img
    src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
    data-src="http://static.com/img.jpg"
    style="display: none;"
/>

DOMContentLoaded事件被触发时,JavaScript会检测视口中的<img />个元素,并将src属性值替换为data-src的值。

问题:

在加载整个DOM之前,首页上的图像不会出现。由于这是一个非常大的页面(2MB HTML),因此在DOMContentLoaded事件被触发之前需要大约3-5秒。

我正在寻找的是一个JavaScript解决方案,它可以让我在DOM中进行操作后立即加载前100个图像。

1 个答案:

答案 0 :(得分:0)

  

我正在寻找的是一个能够让我的JavaScript解决方案   一旦可用,就加载前100个图像   DOM中的操作。

我实施的解决方案基本上就是这个。

我需要一个抽象延迟加载脚本来启用对页面上现有图像的重新索引。我将首先在文档中的其他任何内容之前同步加载此脚本。从JavaScript可以运行的那一刻起,脚本在尝试查找DOM中的所有图像元素并检查它们是否在视口中时启动一个间隔。如果视口中包含元素,则会尝试修改图像元素(data-srcsrc)。这段时间一直持续到DOMContentLoaded被解雇。

就代码而言,它看起来像这样:

const LazyImageLoader = require('./LazyImageLoader');
const domReady = require('domready');

/**
 * The reason for using setTimeout instead of setInterval
 * is to not re-run revalidate more often than the body
 * of the function can be evaluated.
 */
const createIntervalIterator = (callback, interval) => {
  let currentTimeout;

  const control = {};

  const iterator = () => {
    const startTime = new Date().getTime();

    callback();

    const evaluationTime = new Date().getTime() - startTime;

    const delayNextIteration = interval - evaluationTime;

    currentTimeout = setTimeout(iterator, delayNextIteration);
  };

  iterator();

  return () => {
    clearTimeout(currentTimeout);
  };
};

const iterationIntervalTime = 100;

const lazyImageLoader = new LazyImageLoader({
  offset: 100,
  selector: 'img[data-src]',
});

/**
 * Revalidation ensures that all images are in LazyImageLoader index.
 */
const revalidate = () => {
    lazyImageLoader.revalidate();
};

const cancelInterval = createIntervalIterator(() => {
  revalidate();
}, iterationIntervalTime);

domReady(() => {
  if (cancelInterval) {
    cancelInterval();
  }

  // Revalidate after domReady in case any images have been added
  // to the DOM after the last `revalidate` invocation.
  revalidate();
});