资讯专栏INFORMATION COLUMN

quicklink解析

silvertheo / 619人阅读

摘要:等待浏览器空闲后执行。使用方式参考链接源码解析的入口函数接受传入的配置参数,通过函数和默认的配置选项合并。然后在回调中便利传入的数组,如果数组中的元素包含在对象中,则取消对该元素的监视,并对该标签元素所对应的资源进行预加载。

简介

quicklink是一个js库,可以预加载出现在视口的网页链接,提高用户体验。它的加载过程如下:
1.检测网页中的链接是否出现在视口中,等待链接出现在视口,执行步骤2。
2.等待浏览器空闲后执行3。
3.判断当前的网络连接是否是2G,如果是则停止执行,如果不是2G网络,执行步骤4。
4.预加载链接指向资源。

使用方式

参考链接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)) {
   // If there are any filters, the link must not match any of them
   isIgnored(link, ignores) || toPrefetch.add(link.href);
}

如果链接没有被忽略,则将该节点的href属性值加入到toPrefetch中

const toPrefetch = new Set();
toPrefetch.add(link.href);

总的代码逻辑如下

export default function (options) {
  options = Object.assign({
    timeout: 2e3,
    priority: false,
    timeoutFn: requestIdleCallback,
    el: document,
  }, options);

  observer.priority = options.priority;

  const allowed = options.origins || [location.hostname];
  const ignores = options.ignores || [];

  options.timeoutFn(() => {
    // If URLs are given, prefetch them.
    if (options.urls) {
      options.urls.forEach(prefetcher);
    } else {
      // If not, find all links and use IntersectionObserver.
      Array.from(options.el.querySelectorAll("a"), link => {
        observer.observe(link);
        // If the anchor matches a permitted origin
        // ~> A `[]` or `true` means everything is allowed
        if (!allowed.length || allowed.includes(link.hostname)) {
          // If there are any filters, the link must not match any of them
          isIgnored(link, ignores) || toPrefetch.add(link.href);
        }
      });
    }
  }, {timeout: options.timeout});
}
检测link出现在视口

上面通过observer.observe(link)监视节点元素,其中observer是IntersectionObserver对象的实例,被监听的节点对象出现在视口时,会执行new操作时传入的回调函数,并将出现在视口的节点对象通过数组的形式传给该回调。然后在回调中便利传入的数组,如果数组中的元素包含在toPrefetch对象中,则取消对该元素的监视,并对该a标签元素所对应的资源进行预加载。

const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const link = entry.target;
      if (toPrefetch.has(link.href)) {
        observer.unobserve(link);
        prefetcher(link.href);
      }
    }
  });
});
异步函数实现

如果浏览器支持requestIdleCallback,则使用原生的函数,如果不支持,则使用setTimeout函数做ployfill。

const requestIdleCallback = requestIdleCallback ||
  function (cb) {
    const start = Date.now();
    return setTimeout(function () {
      cb({
        didTimeout: false,
        timeRemaining: function () {
          return Math.max(0, 50 - (Date.now() - start));
        },
      });
    }, 1);
  };

export default requestIdleCallback;
资源请求函数实现

预加载策略主要有三种

1. prefetch

function linkPrefetchStrategy(url) {
  return new Promise((resolve, reject) => {
    const link = document.createElement(`link`);
    link.rel = `prefetch`;
    link.href = url;

    link.onload = resolve;
    link.onerror = reject;

    document.head.appendChild(link);
  });
};

2.ajax加载

function xhrPrefetchStrategy(url) {
  return new Promise((resolve, reject) => {
    const req = new XMLHttpRequest();

    req.open(`GET`, url, req.withCredentials=true);

    req.onload = () => {
      (req.status === 200) ? resolve() : reject();
    };

    req.send();
  });
}

3.Fetch请求加载

function highPriFetchStrategy(url) {
  // TODO: Investigate using preload for high-priority
  // fetches. May have to sniff file-extension to provide
  // valid "as" values. In the future, we may be able to
  // use Priority Hints here.
  //
  // As of 2018, fetch() is high-priority in Chrome
  // and medium-priority in Safari.
  return self.fetch == null
    ? xhrPrefetchStrategy(url)
    : fetch(url, {credentials: `include`});
}
网络类型判断
if (conn = navigator.connection) {
    // Don"t prefetch if the user is on 2G. or if Save-Data is enabled..
    if ((conn.effectiveType || "").includes("2g") || conn.saveData) return;
  }

将上面三种预加载方法封装成函数,暴露给外部使用

const supportedPrefetchStrategy = support("prefetch")
  ? linkPrefetchStrategy
  : xhrPrefetchStrategy;

function prefetcher(url, isPriority, conn) {
  if (preFetched[url]) {
    return;
  }

  if (conn = navigator.connection) {
    // Don"t prefetch if the user is on 2G. or if Save-Data is enabled..
    if ((conn.effectiveType || "").includes("2g") || conn.saveData) return;
  }

  // Wanna do something on catch()?
  return (isPriority ? highPriFetchStrategy : supportedPrefetchStrategy)(url).then(() => {
    preFetched[url] = true;
  });
};

export default prefetcher;

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/53529.html

相关文章

  • quicklink解析

    摘要:等待浏览器空闲后执行。使用方式参考链接源码解析的入口函数接受传入的配置参数,通过函数和默认的配置选项合并。然后在回调中便利传入的数组,如果数组中的元素包含在对象中,则取消对该元素的监视,并对该标签元素所对应的资源进行预加载。 简介 quicklink是一个js库,可以预加载出现在视口的网页链接,提高用户体验。它的加载过程如下:1.检测网页中的链接是否出现在视口中,等待链接出现在视口,执...

    Steve_Wang_ 评论0 收藏0
  • 结合 Google quicklink,react 项目实现页面秒开

    摘要:最后,状态管理与同构实战这本书由我和前端知名技术大佬颜海镜合力打磨,凝结了我们在学习实践框架过程中的积累和心得。 对于前端资讯比较敏感的同学,可能这两天已经听说了 GoogleChromeLabs/quicklink这个项目:它由 Google 公司著名开发者 Addy Osmani 发起,实现了:在空闲时间预获取页面可视区域内的链接,加快后续加载速度。如果你没有听说过 Addy Os...

    warkiz 评论0 收藏0
  • 《阿里云前端技术周刊》第二期

    摘要:作者也树校对染陌素材也树英布阿里云前端技术周刊由阿里云智能商业中台体验技术团队整理编写。如何在工作中快速成长致工程师的个简单技巧工程师成长干货,全文提纲如下,图片来自阿里技术公众号关于我们我们是阿里云智能中台体验技术团队。 作者:@也树 校对:@染陌 素材:@也树、@英布 《阿里云前端技术周刊》由阿里云智能商业中台体验技术团队整理编写。 知乎:阿里云中台前端/全栈团队专栏 Github...

    kyanag 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<