通過quicklink讓我們突破性能瓶頸

什么是quicklink

它是谷歌開源又一個(gè)精品庫,其官網(wǎng)是這么說的:

Faster subsequent page-loads by prefetching in-viewport links during idle time(通過空閑時(shí)間預(yù)加載視口中的links資源來讓之后的頁面加載更快)

聽起來是一個(gè)很神奇的功能氧苍,那么它是如何工作的呢:

  • 檢測(cè)視口中的鏈接 (使用 Intersection Observer監(jiān)控)
  • 等待瀏覽器空閑 (使用 requestIdleCallback監(jiān)控)
  • 判斷用戶不是使用的慢網(wǎng)(如2G) (使用 navigator.connection.effectiveType) 或者有啟用了數(shù)據(jù)緩存 (使用 navigator.connection.saveData)
  • 預(yù)加載對(duì)應(yīng)的URL (使用 <link rel=prefetch> 或者 XHR). 提供對(duì)請(qǐng)求優(yōu)先級(jí)的一些控制 (如果支持可切換成fetch()).

怎么用quicklink

功能如此強(qiáng)大寞肖,那使用是不是會(huì)很麻煩呢拐格?不,你錯(cuò)了,讓我們來看看如何簡(jiǎn)單的來使用這個(gè)神奇的庫吧狂打。

安裝

可以采用npm的方式:

npm install --save quicklink

或者
我們可以直接進(jìn)行引用:https://unpkg.com/quicklink@1.0.0/dist/quicklink.umd.js

使用

quicklink 提供了幾種使用的方式:
快速使用:

<!--首先引用umd模式的js -->
<script src="dist/quicklink.umd.js"></script>
<!-- 在任何時(shí)候都可以進(jìn)行初始化 -->
<script>
quicklink();
</script>

你可以在load事件回調(diào)中來初始化书斜。

<script>
window.addEventListener('load', () =>{
   quicklink();
});
</script>

ES Module 的引入:

import quicklink from "quicklink/dist/quicklink.mjs";
quicklink();

quicklink接口參數(shù):

接口 描述 類型 默認(rèn)值
el 在是口中需要被監(jiān)控的容器外殼 dom節(jié)點(diǎn) -
urls 進(jìn)行預(yù)加載的靜態(tài)URL數(shù)組(用來替換el屬性配置的監(jiān)控外殼) Array -
timeout 自定義的延遲時(shí)間诬辈,默認(rèn)為requestIdleCallback,也可以自定義 Function requestIdleCallback
priority 設(shè)置獲取資源的優(yōu)先級(jí) boolean false
origin 設(shè)置預(yù)加載資源的域菩佑,來保證任何域下都可以加載 Array 默認(rèn)相同域
ignores 一個(gè)正則自晰,函數(shù)或者Array,用于進(jìn)一步的確定是否預(yù)取URL RegExp稍坯、Function酬荞、Array -

使用方法

先來段html代碼:

<div  id="demo1"  class="screen">
    <h1>Basic demo</h1>
    <a href="../test/1.html">Link 1</a>
    我是第一個(gè)容器
    <a href="../test/2.html">Link 2</a>
</div>
<div class="screen">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eos, quos?
    <a href="../test/3.html">Link 3</a>
    <section id="stuff">
        <a href="../test/main.css">CSS</a>
    </section>
</div>
<div class="screen">
      <a href="../test/4.html">Link 4</a>
</div>
  1. 我們可以設(shè)置預(yù)加載的位置,這樣可以視口中有很多資源時(shí)瞧哟,也不會(huì)加載混巧,只會(huì)當(dāng)demo1容器到視口時(shí)才會(huì)加載。
let elm = document.getElementById('demo1');
quicklink({
    'el': elm
});

來看看我們的效果(不要在意錯(cuò)誤勤揩,這只是個(gè)demo):


使用el之后的效果
  1. 我們?cè)趤砜纯磸?qiáng)制設(shè)置urls咧党,這樣就不會(huì)來判斷視口位置了。
quicklink({
    urls: ['2.html','3.html', '4.js']
});
強(qiáng)制設(shè)置URL之后
  1. 默認(rèn)為低優(yōu)先級(jí)(priority為false)系統(tǒng)會(huì)使用prefetch陨亡。對(duì)于高優(yōu)先級(jí)傍衡,會(huì)使用fetch()深员,或者XHR。
quicklink({ priority: false });
低優(yōu)先級(jí)時(shí)
quicklink({ priority: true });
高優(yōu)先級(jí)

源碼解析

我們的主要目的是來研究一下這個(gè)庫是如何來實(shí)現(xiàn)這些神奇的功能的蛙埂。
整個(gè)項(xiàng)目中有比較重要API我們需要了解倦畅。

  1. 可以用來監(jiān)控視口的功能API IntersectionObserver
  2. 可以提前預(yù)加載 prefetch

首先我們先監(jiān)控整個(gè)瀏覽器的視口:

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);
      }
    }
  });
});

當(dāng)獲取到需要提前預(yù)加載的資源文件URL之后,判斷用戶當(dāng)前網(wǎng)絡(luò)绣的,如果是非2G網(wǎng)絡(luò)時(shí)叠赐,我們才會(huì)進(jìn)行資源預(yù)加載:

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;
  });
};

當(dāng)isPriority優(yōu)先級(jí)為高時(shí)調(diào)用highPriFetchStrategy,優(yōu)先級(jí)為低時(shí)調(diào)用supportedPrefetchStrategy屡江。

highPriFetchStrategy

如果優(yōu)先級(jí)為高時(shí)芭概,首先我們會(huì)采用Fetch,如果不支持惩嘉,則降級(jí)為XHR進(jìn)行加載:

function highPriFetchStrategy(url) {
  return self.fetch == null
    ? xhrPrefetchStrategy(url)
    : fetch(url, {credentials: `include`});
}

supportedPrefetchStrategy

如果優(yōu)先級(jí)為低時(shí)罢洲,我們會(huì)優(yōu)先使用prefetch,如果不支持宏怔,會(huì)降級(jí)使用XHR進(jìn)行加載:

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

我們?cè)趤砜纯搓P(guān)鍵的2個(gè)函數(shù) xhrPrefetchStrategylinkPrefetchStrategy

  • xhrPrefetchStrategy:函數(shù)中會(huì)直接使用get請(qǐng)求進(jìn)行一起http請(qǐng)求:
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();
  });
}
  • linkPrefetchStrategy:我們會(huì)動(dòng)態(tài)創(chuàng)建一個(gè)link奏路,并且使用prefetch來進(jìn)行pretch預(yù)加載:
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);
  });
};

總結(jié)一下:

來了一個(gè)比較渣渣的流程圖;


整體quicklink流程圖

相關(guān)文檔

Resource Hints
https://github.com/GoogleChromeLabs/quicklink

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末臊诊,一起剝皮案震驚了整個(gè)濱河市鸽粉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌抓艳,老刑警劉巖触机,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異玷或,居然都是意外死亡儡首,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門偏友,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蔬胯,“玉大人,你說我怎么就攤上這事位他》毡簦” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵鹅髓,是天一觀的道長舞竿。 經(jīng)常有香客問我,道長窿冯,這世上最難降的妖魔是什么骗奖? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上执桌,老公的妹妹穿的比我還像新娘鄙皇。我一直安慰自己,他們只是感情好鼻吮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布育苟。 她就那樣靜靜地躺著较鼓,像睡著了一般椎木。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上博烂,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天香椎,我揣著相機(jī)與錄音,去河邊找鬼禽篱。 笑死畜伐,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的躺率。 我是一名探鬼主播玛界,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼悼吱!你這毒婦竟也來了慎框?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤后添,失蹤者是張志新(化名)和其女友劉穎笨枯,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體遇西,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡馅精,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了粱檀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洲敢。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖茄蚯,靈堂內(nèi)的尸體忽然破棺而出压彭,到底是詐尸還是另有隱情,我是刑警寧澤第队,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布哮塞,位于F島的核電站,受9級(jí)特大地震影響凳谦,放射性物質(zhì)發(fā)生泄漏忆畅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望家凯。 院中可真熱鬧缓醋,春花似錦、人聲如沸绊诲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽掂之。三九已至抗俄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間世舰,已是汗流浹背动雹。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留跟压,地道東北人胰蝠。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像震蒋,于是被迫代替她去往敵國和親茸塞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容