My Little World

懒加载

lazy

图片lazyload

基本原理是图片image标签的src属性在构建DOM时,先给一特定的默认值,可以是本地图片路径,然后通过监听scroll事件,
判断图片所在位置是否在可视屏幕里面,如果在可视屏幕里面,就将要加载的真正图片资源给到image的src属性
当然通过判断src的值是否是默认值,就可以知道图片是否已经被加载过,加载过就不会被从新赋值,然后重新加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function lazyload() {
const images = document.getElementsByTagName('img')
const len = images.length
let n = 0
return function() {
console.log(1)
const seeHeight = document.documentElement.clientHeight
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
for (let i = n; i < len; i++) {
if (images[i].offsetTop < seeHeight + scrollTop) { //是否在可视范围
if (images[i].getAttribute('src') === '默认图片的url') {
images[i].src = images[i].getAttribute('data-src') //赋值资源链接
}
n = n + 1
}
}
}
}
var loadImages = lazyload()
window.onload = function () {
loadImages()
window.addEventListener('scroll', loadImages, false)
}

但缺点就是,只要触发了scroll事件,就会去调函数,无论图片有没有被加载,这样就会造成一些没用的调用,所以对此进行改进

改进方式一:使用节流阀(Throttle)

响应函数函数在一定时间内只允许被调用一次,函数能否被执行根据时间来确定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function throttle(fn, delay, atleast) {
let timeout = null
let startTime = new Date()
return function() {
const curTime = new Date()
clearTimeout(timeout) //3,取消限定时间内预约的将来的函数执行,防止多次执行
if (curTime - startTime >= atleast) {//1,超过限定时间,执行一次
fn()
startTime = curTime
} else {
timeout = setTimeout(fn, delay) //2,没超过限定时间,在限定时间内不执行,延续时间到超过限定时间后再执行
}
}
}
var loadImages = lazyload()
window.onload = function () {
loadImages()
window.addEventListener('scroll', throttle(loadImages, 500, 1000), false)
}

改进方式二:使用防抖动技术(debounce)

当事件发生时,不会立即激活回调。
等待一定的时间并检查相同的事件是否再次触发。
如果是,重置定时器,并再次等待。
如果在等待期间没有发生相同的事件,等待时间结束后就立即激活回调。

1
2
3
4
5
6
7
8
9
10
11
12
13
function debounced(fn,delay) {
clearTimeout(timeoutID); // reset timer
timeoutID = setTimeout(function() {
// wait for some time
// and check if event happens again
fn()
}, delay);
};
var loadImages = lazyload()
window.onload = function () {
loadImages()
window.addEventListener('scroll', debounced(loadImages, 500), false)
}

组件的lazyload

实现一:AMD模式require实现异步加载模块
在AMD模式里面每个模块都会被define包裹,对无序的代码进行有序的模块化定义,目的就是为了使js能够按照一定秩序执行,
require模块时,会根据模块之间的依赖关系按顺序加载

实现二:使用require.ensure()方法调用异步模块,配置chunkFilename为异步模块要打包到的地方,webpack打包时,就会根据依赖关系打包成异步加载的模式,在运行时就会异步加载模块

实现三:将组建都标签化后,通过对标签添加是否异步的标志,从而实现对该组件的异步加载

预加载技术

1.提前加载下一页数据
2.加载页面时,尽早发出数据请求,实现页面数据预加载

图片的 base64 编码

图片的 base64 编码就是可以将一图片数据编码成一串字符串,使用该字符串代替代码中的图像地址
图片就可以随着HTML的下载同时下载到本地,不用为了下载图片向服务器发出请求

将图片转化为Base64编码的工具,可以使用线上网站,也可以用以下方法
在 chrome 下打开新的标签页,然后把要转化的图片直接拖入浏览器,打开控制台,点 Source,source的内容内容就是图片base64编码

可以看到一个图片的base64编码的字符数量一般是很大的,这样,当把图片编码无论是写到css文件还是html文件,
都会因为解析时间过长从而造成渲染速度下降,因此将图片进行base64编码最好的应用场景是如下情况:
如果图片足够小且因为用处的特殊性无法被制作成雪碧图(CssSprites),在整个网站的复用性很高且基本不会被更新

base64 编码

Angular会自动为每个拥有作用域的DOM节点加上 ng-scope 类
AngularJs的angular.extend()方法可以把一个或多个对象中的方法和属性扩展到一个目的对象中,使得这个对象拥有其他对象相同的方法和属性
angular.extends()方法的第一个参数是要被扩展的对象,后面可以传入一个或多个对象

补充

优化占位图

VG元素/提取图片背景色以base64形式直出
使用SVG画图形轮廓,再加一个模糊滤镜
对图片进行二值化提取剪影

浏览器渲染图片原理

构建DOM树,遇到img标签加载图片
构建样式树,遇到backgroud-img图片不加载
构建render树,所有属性都会构建,如果元素有display:none属性,则其子元素不被构建
渲染DOM树,仅渲染没有display:none属性的元素,如果发现元素有该属性则不进行渲染;没有被构建的子元素背景图片不会被加载更不会被加载

设置了display:none属性的元素,图片不会渲染出来,但会加载,不管是直接的img属性还是div的背景图片都会被加载

1
2
3
4
5
6
7
8
<img src="https://cdn-jlsq-img.thy360.com/2e3457ef739c4116847eb359dffcf651.jpg!thumbnail"> //加载
<div class="skslsl"></div>//加载
<style type="text/css">
.skslsl{
background-image:url('https://cdn-jlsq-img.thy360.com/3aeac46295cb4f15bfb1154692e00c95.JPEG');

}
</style>

设置了display:none属性元素的子元素,样式表中的背景图片不会渲染出来,也不会加载;而img标签的图片不会渲染出来,但会加载。

1
2
3
4
5
6
7
8
9
10
11
<div style="display: none;">
<img src="https://cdn-jlsq-img.thy360.com/2e3457ef739c4116847eb359dffcf651.jpg!thumbnail"> //加载
<div class="skslsl"></div>//不加载
</div>

<style type="text/css">
.skslsl{
background-image:url('https://cdn-jlsq-img.thy360.com/3aeac46295cb4f15bfb1154692e00c95.JPEG');

}
</style>

当触发伪类的时候,伪类样式上的背景图片才会加载。

重复图片只加载一次,是因为加载一次后,之后的加载均从缓存中读取;
链接