当前位置: 首页 > Web前端 > HTML5

quicklink分析

时间:2023-04-05 17:32:51 HTML5

简介quicklink是一个js库,可以预加载出现在viewport中的网页链接,提高用户体验。它的加载过程如下:1.检测网页中的链接是否出现在视口中,等待链接出现在视口中,然后执行步骤2。2.等待浏览器空闲,执行3.3.判断当前网络连接是否为2G,如果是,则停止执行,如果不是2G网络,转4.4.preload链接指向资源。使用方法参考链接https://github.com/GoogleChro...quicklink源码分析quicklink的入口函数接受传入的配置参数,通过Object.assign函数将其与默认的配置选项合并。然后执行timeoutFn异步方法,该方法接收一个回调函数。回调中的主要逻辑如下:如果传入的options参数有urls属性,则直接执行预加载;否则,通过document.querySelectorAll方法获取所有a标签元素的NodeList,然后方便元素节点列表,监听元素节点observer.observe(link);然后判断a元素对象的href属性值所属的域名是否允许访问,如果允许访问,继续判断该链接是否应该被忽略,判断逻辑如下:if(!allowed.length||allowed.includes(link.hostname)){//如果有任何过滤器,链接不得匹配其中任何一个isIgnored(link,ignores)||预取。add(link.href);}如果没有忽略链接,将节点的href属性值添加到toPrefetchconsttoPrefetch=newSet();toPrefetch.add(link.href);整体代码逻辑如下observer.priority=options.priority;const允许=options.origins||[位置.主机名];const忽略=options.ignores||[];options.timeoutFn(()=>{//如果给出了URL,预取它们。if(options.urls){options.urls.forEach(prefetcher);}else{//如果没有,找到所有链接并使用IntersectionObserver。Array.from(options.el.querySelectorAll('a'),link=>{observer.observe(link);//如果锚点匹配允许的来源//~>A`[]`或`true`意味着一切isallowedif(!allowed.length||allowed.includes(link.hostname)){//如果有任何过滤器,链接不得匹配其中任何一个isIgnored(link,ignores)||toPrefetch.add(link.href);}});}},{timeout:options.timeout});}通过observer.observe(link)检测链接出现在viewport上,并监听节点元素,其中observer是IntersectionObserver对象的一个??实例。当监听到的节点对象出现在视口中时,会执行new操作时传入的回调函数,并将出现在视口中的节点对象以数组的形式传递给回调,然后回调传入的数组很方便。如果数组中的元素包含在toPrefetch对象中,则取消对该元素的监听,预加载a标签元素对应的资源。constobserver=newIntersectionObserver(entries=>{entries.forEach(entry=>{if(entry.isIntersecting){constlink=entry.target;if(toPrefetch.has(link.href)){观察者.unobserve(链接);预取器(link.href);}}});});异步函数实现如果浏览器支持requestIdleCallback,使用native函数,如果不支持,使用setTimeout函数作为polyfill。常量requestIdleCallback=requestIdleCallback||函数(cb){常量开始=Date.now();returnsetTimeout(function(){cb({didTimeout:false,timeRemaining:function(){returnMath.max(0,50-(Date.now()-start));},});},1);};导出默认requestIdleCallback;资源请求函数主要有三种预加载策略1.prefetchfunctionlinkPrefetchStrategy(url){returnnewPromise((resolve,reject)=>{constlink=document.createElement(`link`);link.rel=`prefetch`;link.href=url;link.onload=resolve;link.onerror=reject;document.head.appendChild(link);});};2.ajaxloadingfunctionxhrPrefetchStrategy(url){returnnewPromise((resolve,reject)=>{constreq=newXMLHttpRequest();req.open(`GET`,url,req.withCredentials=true);req.onload=()=>{(req.status===200)?resolve():reject();};req.send();});}3.Fetch请求加载函数highPriFetchStrategy(url){//TODO:调查使用预加载进行高优先级//提取。可能必须嗅探文件扩展名以提供//有效的“as”值。将来,我们可能可以//在此处使用优先级提示。////截至2018年,fetch()在Chrome中为高优先级//在Safari中为中等优先级。返回self.fetch==null?xhrPrefetchStrategy(url):fetch(url,{credentials:`include`});}网络类型判定if(conn=navigator.connection){//如果用户在2G上,则不要预取。或者如果启用了保存数据..if((conn.effectiveType||'').includes('2g')||conn.saveData)return;}将上面三种预加载方法封装成函数,暴露给外部使用constsupportedPrefetchStrategy=support('prefetch')?linkPrefetchStrategy:xhrPrefetchStrategy;functionprefetcher(url,isPriority,conn){if(preFetched[url]){返回;}if(conn=navigator.connection){//如果用户使用2G,则不要预取。或者如果启用了保存数据..if((conn.effectiveType||'').includes('2g')||conn.save数据)返回;}//想在catch()上做点什么吗?return(isPriority?highPriFetchStrategy:supportedPrefetchStrategy)(url).then(()=>{preFetched[url]=true;});};导出默认预取器;