Intersection Observer API
提供了一种异步观察目标元素与祖先元素或顶级文档viewport的“交集"中的变化的方法。css
一直以来,检测元素的可视状态或者两个元素的相对可视状态都不是件容易事,毕竟大部分解决办法并不是彻底可靠,也极易拖慢整个网站的性能。然而,随着网页发展,对上述检测的需求也随之增长了。多种状况下都须要用到元素交集变化的信息,好比:前端
以往咱们的作法是绑定容器的scroll
事件,或者设定时器不停地调用getBoundingClientRect()
获取元素位置,可是这些代码都是在主线程上运行。因此这样作的性能会有必定的影响。vue
咱们如今的mall-core里的imglazyload就是用的传统的方式react
var observer = new IntersectionObserver(callback, options)
数组
以上代码会返回一个IntersectionObserver
实例,callback是当元素的可见性变化时候的回调函数,options是一些配置项(可选)浏览器
返回的这个实例呢,也比较简单,有三个方法。缓存
observer.observe(ele)
observer.unobserve(ele)
observer.disconnect()
Intersection observer options
传递到IntersectionObserver()构造函数的 options 对象,容许控制调用观察者的回调的环境。它也是有3个字段安全
getboundingClientRect()
经过该图就能够知道,本来被观察的元素在经过rootMargin扩大后,会提早触发callback
设置为 [0, 0.5, 1] 就是指当元素出现0%、50%、100%时都会触发callback服务器
callback
当元素的可见性发生变化时,就会触发callback函数。网络
function callback(entries, observer) { // 回调接受两个参数,一个是IntersectionObserverEntry数组,一个是obsever本身 for (var i = 0; i < entries.length; i++) { console.log(entries[i]); } }
请留意,你注册的回调函数将会在主线程中被执行。因此该函数执行速度要尽量的快。若是有一些耗时的操做须要执行,建议使用 Window.requestIdleCallback() 方法。
须要注意的是
因为观察名叫交叉,因此第一思惟会是和边相交,很容易理解为元素和根元素的边相交,实际上这里的触发方式并非说必定就是和根元素的边相交,而是元素的可见性出如今根元素总体视窗内就算相交。
接下来,就用这个来作一个简易的懒加载模块
核心代码
import { useEffect } from 'react'; function loadImg(entries, observer) { for (var i = 0; i < entries.length; i++) { const img = entries[i].target; var src = img.getAttribute("data-src"); console.log(entries[i]); if (entries[i].isIntersecting) { img.src = src; img.removeAttribute("data-src"); img.classList.remove('imglazy'); observer.unobserve(img); // 实验0.5,1 解开 } } } function observerImgs(className, observer) { const imgs = document.querySelectorAll(`img.${className}`); if(!imgs.length) { return; } imgs.forEach((img) => { observer.unobserve(img); observer.observe(img); }); } function useImgLazy(className, list) { useEffect(() => { const observer = new IntersectionObserver(loadImg,{ // root: document.querySelector('.product_list'), // rootMargin: '0px', threshold: [0.5, 1] }); observerImgs(className, observer); return () => { observer.disconnect(); }; }, [className, list]); } export default useImgLazy;
为了观察更直观,因此demo是用的0.5露出才变动src
MutationObserver接口提供了监视对DOM树所作更改的能力。它被设计为旧的Mutation Events功能的替代品,该功能是DOM3 Events规范的一部分。
MutationObserver
构造函数只有一个callback参数,callback和上面的相似,一个是被改动的MutationRecord
数组,一个是观察对象。
实例拥有3个方法
阻止 MutationObserver
实例继续接收的通知,直到再次调用其observe()方法,该观察者对象包含的回调函数都不会再被调用。
配置MutationObserver
在DOM更改匹配给定选项时,经过其回调函数开始接收通知。
从MutationObserver
的通知队列中删除全部待处理的通知,并将它们返回到MutationRecord
对象的新Array中,什么是待处理呢,由于这里的全部操做都是异步的,takeRecords 马上执行。
observe 方法须要提供两个参数
DOM树中的一个要观察变化的DOM Node (多是一个Element) , 或者是被观察的子节点树的根节点。
一个可选的MutationObserverInit
对象,此对象的配置项描述了DOM的哪些变化应该提供给当前观察者的callback。当监听的时候,里面的属性至少有一个为true,不然会抛出异常。
mutationObserver.observe(content, { attributes: true, // Boolean - 观察目标属性的改变 characterData: true, // Boolean - 目标节点或子节点树中节点所包含的字符数据的变化 childList: true, // Boolean - 目标节点(若是subtree为true,则包含子孙节点)添加或删除新的子节点。默认值为false。 subtree: true, // Boolean - 目标以及目标的后代改变都会观察,就是若是这个值为true,其余属性为true后就会都包含子节点。 attributeOldValue: true, // Boolean - 表示须要记录改变前的目标属性值 characterDataOldValue: true, // Boolean - 设置了characterDataOldValue能够省略characterData设置 // attributeFilter: ['src', 'class'] // Array - 观察指定属性 });
mutationRecord数组里的属性有
MutationRecord = { type:若是是属性变化,返回"attributes",若是是一个CharacterData节点(Text节点、Comment节点)变化,返回"characterData",节点树变化返回"childList" target:返回影响改变的节点 addedNodes:返回添加的节点列表 removedNodes:返回删除的节点列表 previousSibling:返回分别添加或删除的节点的上一个兄弟节点,不然返回null nextSibling:返回分别添加或删除的节点的下一个兄弟节点,不然返回null attributeName:返回已更改属性的本地名称,不然返回null attributeNamespace:返回已更改属性的名称空间,不然返回null oldValue:返回值取决于type。对于"attributes",它是更改以前的属性的值。对于"characterData",它是改变以前节点的数据。对于"childList",它是null }
主要知道了哪些元素哪些属性发生了某些变化后,能够针对性的对某个元素作一些操做。
演示demo
PerformanceObserver
用于监测性能度量事件,在浏览器的性能时间轴记录下一个新的 performance entries 的时候将会被通知 。
它会实时的根据每一个资源的加载来通知。
const observer = new PerformanceObserver(performanceCallBack); observer.observe({entryTypes: ['paint', 'resource']}); observer.disconnect(); observer.takeRecords();
其中,callback里第一个参数是PerformanceObserverEntryList
,有一个getEntries
方法,能够取得监控的list,第二个参数是observer对象。
说到这个吧,就得说Performance.timing
和performance.getEntries()
了
对好比下
1:在window.onload
函数里面咱们进行loadEventEnd的取值会取不到,而在PerformanceObserver则不存在这样的问题;
2:使用PerformanceObserver
咱们发现没有navigationStart,domLoading的值。
3:PerformanceObserver
更精确。
【Prompt for unload】- 用户跳转行为(在地址栏输入url后按回车,或者点击a标签跳转等) navigationStart、startTime // 当前浏览器窗口的前一个网页关闭开始执行的时间戳 unloadStart // 前一个页面unload触发开始时间戳 【unload】- 前一个页面unload时间 unloadEnd // 前一个页面unload触发结束时间戳 redirectStart // 返回第一个HTTP跳转开始时的时间戳若是没有跳转,或者不是同一个域名内部的跳转,则返回值为0 【redirect】- 重定向 redirectEnd // 返回最后一个HTTP跳转结束时(即跳转回应的最后一个字节接受完成时)的时间戳,若是没有跳转,或者不是同一个域名内部的跳转,则返回值为0 fetchStart // 返回浏览器准备使用HTTP请求读取文档时的时间戳。该事件在网页查询本地缓存以前发生 【App cache】- 网页查询本地缓存 domainLookupStart // 返回域名查询开始时的时间戳。若是使用持久链接,或者信息是从本地缓存获取的,则返回值等同于fetchStart属性的值 【DNS】- 域名查询 domainLookupEnd // 返回域名查询结束时的时间戳。若是使用持久链接,或者信息是从本地缓存获取的,则返回值等同于fetchStart属性的值 connectStart // 返回创建TCP连接开始向服务器发送时的时间戳。若是使用持久链接(persistent connection),则返回值等同于fetchStart属性的值 【TCP】 secureConnectionStart // 它的值是安全链接握手以前的时刻。若是该属性不可用,则返回undefined。若是该属性可用,但没有使用HTTPS,则返回0 connectEnd // 返回浏览器与服务器之间的链接创建时的时间戳。若是创建的是持久链接,则返回值等同于fetchStart属性的值。链接创建指的是全部握手和认证过程所有结束 回浏览器与服务器开始安全连接的握手时的时间戳。若是当前网页不要求安全链接,则返回0 requestStart // 返回浏览器向服务器发出HTTP请求时(或开始读取本地缓存时)的时间戳 【Request】 - 网络请求 responseStart // 返回浏览器从服务器收到(或从本地缓存读取)第一个字节时的时间戳 【Response】 responseEnd // 返回浏览器从服务器收到(或从本地缓存读取)最后一个字节时(若是在此以前HTTP链接已经关闭,则返回关闭时)的时间戳 domLoading // 返回当前网页DOM结构开始解析时(即Document.readyState属性变为“loading”、相应的readystatechange事件触发时)的时间戳 【Processing】 domInteractive // 返回当前网页DOM结构结束解析、开始加载内嵌资源时(即Document.readyState属性变为“interactive”、相应的readystatechange事件触发时)的时间戳 domContentLoadedEventStart // 返回当前网页DOMContentLoaded事件发生时(即DOM结构解析完毕、全部脚本开始运行时)的时间戳 domContentLoadedEventEnd // 返回当前网页全部须要执行的脚本执行完成时的时间戳 domComplete // 返回当前网页DOM结构生成时(即Document.readyState属性变为“complete”,以及相应的readystatechange事件发生时)的时间戳 loadEventStart // 返回当前网页load事件的回调函数开始时的时间戳。若是该事件尚未发生,返回0 【onLoad】- window.onLoad触发 loadEventEnd // 返回当前网页load事件的回调函数运行结束时的时间戳。若是该事件尚未发生,返回0。经过while循环持续判断直到loadEventEnd>0则表示彻底加载完毕了!网络再也不有任何数据请求、dom也渲染完毕了
demo;
前端性能中,有一些比较重要的指标,好比
白屏时间
首屏时间
那白屏时间其实就是用咱们的页面第一个内容渲染出来时的时间,就是白屏时间,js、css的加载都是会阻塞页面的渲染的。
首屏时间的话的话有多种方式计算,标准也不同,这里很少描述了。
延伸。优化首页性能~~~