1、概述:
    本文将说明 为何需要进行图片懒加载、如何进行图片懒加载、如何进一步优化。
2、为何需要进行图片懒加载?
    在实际的开发中经常会遇到一个页面的内容过多,当前视窗展示不下的情况(特别是移动端),为了减少资源请求 数,加快页面渲染(此处可扩展),可以进行图片懒加载。
3、如何进行图片懒加载?
    图片懒加载的基本思路为
        (1) img标签设置宽高占位,但先不设置src属性,可用data-src等自定义属性代替 (使用背景图可能是更好的做法)
        (2) 监听滚动事件,等待img元素出现在窗口可视范围内时,使用data-src替换src属性
    那么由此引申出一个问题,如何判断img元素出现在窗口可视范围内,一个常用的方案是 img.getBoundingClientRect().top < document.documentElement.clientHeight
        其中 getBoundingClientRect 方法,获取的是元素与浏览器窗口可视范围边界的距离,随着滚动而改变
        document.documentElement.clientHeight 指的是html的可视高度,即浏览器窗口可视范围的高度,不随滚动而改变
        那么当 img.getBoundingClientRect().top > document.documentElement.clientHeight 时,说明img元素还在可视窗口的下方区域,即当前不可见
4、如何进行优化?
    上文的解决思路中需要监听滚动事件,反复读取 img.getBoundingClientRect().top 来判断其是否出现在可视范围中,但是使用 getBoundingClientRect 方法带来的一个问题是将造成浏览器的回流
    浏览器的回流将导致 重新计算样式表、重新生成布局树、重新生成渲染列表,这是一个比较大的开销 (其他可能造成回流的做法包括读取offset系列、读取scroll系列、读取client系列、调用 getComputedStyle 等)
    为了减少这种开销,可以使用防抖和节流
5、防抖节流
    节流:通常利用时间戳,在函数执行时与上一次执行时间进行对比,间隔过小时不予理会,以达到稀释执行次数的目的,他的问题是可能导致最后一次函数未被调用
    防抖:利用setTimeout,延迟执行函数,若在延迟时间范围反复触发,则取消上一次的setTimeout重新设置,他的问题是触发频发时可能仅执行一次
    手写节流+防抖:综合两者的问题实现一个合并版本
    需求:在频繁触发的背景下,降低函数的执行间隔,并保证函数最后一次被执行
    要点:传入两个参数,其一为业务回调,其二为延迟时间,返回包装后的函数,注意业务回调函数的参数处理
    function lazy(cb, delay) {
       let timer
       let last = Date.now()
       return function() {  // 注意不能用箭头函数,因为没有 arguments,如过要用也可以改成剩余参数
           let args = arguments
           let now = Date.now()
           let done = false
           if(now - last > delay) {
               cb.apply(this, args)
               last = now
               done = true
           }
           if(!done) {
               if(timer) {
                   clearTimeout(timer)
                   timer = null
               }
               timer = setTimeout(() => {
                   cb.apply(this, args)
               }, delay)
           }
       }
    }
    document.addEventListener('scroll', lazy(function() {
        // 业务代码
        console.log(arguments) // 打印出的是事件对象
    }, 500))