最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue首屏?xí)r間指標(biāo)采集最佳方式詳解

 更新時(shí)間:2023年01月10日 16:18:30   作者:皮皮大人  
這篇文章主要為大家介紹了Vue首屏?xí)r間指標(biāo)采集最佳方式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

SPA項(xiàng)目中,首屏加載速度都是老生常談的問(wèn)題了,首屏?xí)r間直接反應(yīng)了用戶多久能看到頁(yè)面的主要內(nèi)容,這決定了用戶體驗(yàn),本文聊一聊如何采集首屏?xí)r間,本文主要是單指正常記錄首屏?xí)r間(不和首屏js資源報(bào)錯(cuò)等等掛鉤)

Performance

timing

  • connectStart:HTTP域名解析完成的時(shí)間
  • connectEnd:HTTP瀏覽器與服務(wù)器之間連接建立完成的時(shí)間
  • domComplete:DOM文檔解析完成,readyState變?yōu)閏omplete
  • domContentLoadedEventStart:所有腳本已經(jīng)執(zhí)行完,開(kāi)始執(zhí)行DOMContentLoaded方法
  • domContentLoadedEventEnd:執(zhí)行DOMContentLoaded方法結(jié)束
  • domInteractive:DOM結(jié)構(gòu)加載結(jié)束,開(kāi)始加載內(nèi)嵌資源,readyState變?yōu)閕nteractive
  • domLoading:DOM結(jié)構(gòu)開(kāi)始解析,readyState開(kāi)始是loading
  • domainLookupStart:DNS域名查詢開(kāi)始
  • domainLookupEnd:DNS域名查詢結(jié)束
  • fetchStart:瀏覽器發(fā)起任何請(qǐng)求之前的時(shí)間戳
  • loadEventStart:開(kāi)始加載load事件
  • loadEventEnd:load事件加載結(jié)束
  • navigationStart:unload上一個(gè)文檔的時(shí)間節(jié)點(diǎn)
  • redirectStart:第一個(gè)頁(yè)面重定向開(kāi)始的時(shí)間
  • redirectEnd:最后一個(gè)頁(yè)面重定向結(jié)束的時(shí)間
  • requestStart:瀏覽器向服務(wù)器發(fā)起HTTP請(qǐng)求(包含緩存,本地資源)
  • responseStart:瀏覽器從服務(wù)器收到HTTP請(qǐng)求返回的第一個(gè)字節(jié)的時(shí)間
  • responseEnd:瀏覽器從服務(wù)器收到HTTP請(qǐng)求返回的最后一個(gè)字節(jié)的時(shí)間
  • secureConnectionStart:HTTPS協(xié)議握手之前的時(shí)間,如果非HTTPS,則為0
  • unloadEventStart:上一個(gè)文檔unload事件的開(kāi)始時(shí)間(需要是同源文檔,否則為0)
  • unloadEventEnd:上一個(gè)文檔unload事件的結(jié)束時(shí)間(需要是同源文檔,否則為0)

那么首屏的時(shí)間是不是可以簡(jiǎn)單取值為:

domComplete - navigationStart

答案是不可以的,因?yàn)樵赩ue和React等SPA框架中,頁(yè)面是空的,需要加載js,然后通過(guò)js腳本來(lái)把頁(yè)面內(nèi)容渲染出

來(lái),所以上面簡(jiǎn)單的運(yùn)算是得不到真正首屏?xí)r間的

自動(dòng)化采集和思考

手動(dòng)化采集侵入代碼性強(qiáng),而且也無(wú)法一勞永逸,可能也導(dǎo)致數(shù)據(jù)不夠標(biāo)準(zhǔn),所以這里我采用的方式自動(dòng)化采集,就是用一段代碼來(lái)做首屏的自動(dòng)化采集。這里思考熱門方式:

MutationObserver  監(jiān)聽(tīng)根節(jié)點(diǎn)的 dom 節(jié)點(diǎn)數(shù)量

當(dāng)然還有個(gè)方案,計(jì)算計(jì)算FMP 如何相對(duì)準(zhǔn)確的計(jì)算 FMP (當(dāng)然我這里沒(méi)有使用該文章的方式,因?yàn)橛X(jué)得執(zhí)行起來(lái)太過(guò)復(fù)雜)

此 API 監(jiān)聽(tīng)頁(yè)面 DOM 變化,并告訴我們每次變化的 DOM 是被增加還是刪除

MutationObserver缺點(diǎn): 無(wú)法兼容骨架屏有無(wú)的情況,如果頁(yè)面有骨架屏,也沒(méi)法真正檢測(cè)出真正的白屏?xí)r間

而且難以決定什么是加載頁(yè)面完成的標(biāo)記

我的方案

實(shí)現(xiàn):

其實(shí)我的思考的方案很簡(jiǎn)單,核心代碼其實(shí)只有兩行,就是通過(guò) Vue.mixin() 混入組件 mounted 的時(shí)間,然后統(tǒng)計(jì)每個(gè)組件的加載在頁(yè)面上的時(shí)間,最后一個(gè)組件加載的時(shí)間就是用戶看到的首屏?xí)r間(因?yàn)樗薪M件已經(jīng)加載完畢,不包括異步組件)

import Vue from 'vue';
class whiteScreen {
    constructor() {
        const timing = window.performance.timing;
        // 記錄開(kāi)始時(shí)間
        this.startTime = timing.navigationStart || timing.connectStart || 
        dayjs().format('YYYY-MM-DD HH:mm:ss:SSS');
        // 加載中狀態(tài) 
        this.loading = false;
        // 收集每個(gè)組件加載的完成數(shù)據(jù)
        this.times = [];
        // 記錄組件是否加載過(guò),因?yàn)橐粋€(gè)頁(yè)面會(huì)多次用到某組件,只記錄第一次加載成功即可
        this.isLoadedComp = {};
        // 是否在加載中
        this.setLoading(true);
        // 利用vue的mixin記錄每個(gè)組件掛載完成的時(shí)間
        const _this = this;
        Vue.mixin({
            /** 
            * 注意這里要用到mounted而不是created,因?yàn)槲覀円涗洶灼恋臅r(shí)間
            * 所以是用戶看到界面的時(shí)刻,用mounted比created更加適合,具體看 vue 組件的生命周期 
            * 另外vue在組件和子組件加載機(jī)制。created和mounted執(zhí)行時(shí)機(jī)也存在區(qū)別 
            */
            mounted() {
            // 如果不是正在加載中,則返回
            if (!_this.isLoading()) return;
            // 獲取組件標(biāo)簽
            const name = this.$options.name || this.$options._componentTag;
            // 如果該組件已經(jīng)加載過(guò),則不用再記錄
            if (_this.isCompLoaded(name)) return;
            this.$nextTick(() => {
                if (name) {
                    _this.push({
                    name: name,
                    // 記錄當(dāng)前組件加載成功的時(shí)間
                    time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
             });
            }
           });
          }
      });
    }
    isLoading() {
        return this.loading;
    }
    setLoading(value) {
      this.loading = value;
      if (!this.isLoading()) {
        const data = [...this.times];
        const startTime = this.startTime;
        // TODO: 上傳埋點(diǎn)
        console.log({
          data,
          startTime,
        });
      }
    }
    isCompLoaded(name) {
      if (!this.isLoadedComp[name]) {
        this.isLoadedComp[name] = true;
        return false;
      }
      return this.isLoadedComp[name];
    }
}

解釋一下上述代碼,如上面所說(shuō)的,用了Vue.mixin的方式記錄每個(gè)組件的加載的完成時(shí)間,上面有個(gè)對(duì)象 isLoadedComp 用來(lái)記錄頁(yè)面是否加載過(guò)組件,舉個(gè)例子說(shuō)明:

page含有A組件,但是A組件在page有被多次使用到,所以我們只需要第一次加載作為依據(jù)即可

使用了這段代碼后,我們就會(huì)得到這樣如下的 data 數(shù)據(jù)結(jié)構(gòu),如下圖:

這樣我們準(zhǔn)確的取得了頁(yè)面加載每個(gè)組件用到的時(shí)間,但是還存在一個(gè)問(wèn)題,上面的 loading 狀態(tài)應(yīng)該何時(shí)結(jié)束,我們要根據(jù)什么作為頁(yè)面加載完成的依據(jù),這里大家不妨思考下

設(shè)置組件最大加載時(shí)間

來(lái)看看這種情況,頁(yè)面 page 有異步組件的情況,page有10個(gè)組件,2個(gè)組件是異步,8個(gè)同步組件,加載同步組件需要2面,加載異步組件需要10秒,理論上我們的白屏?xí)r間應(yīng)該2s,而不是8秒,因?yàn)榇藭r(shí)用戶已經(jīng)能看到界面,并且可以做一些有效點(diǎn)擊操作,所以我們結(jié)合上面的,什么作為頁(yè)面加載完成的依據(jù)得出我們的設(shè)計(jì)方式

這樣我們可以設(shè)置一個(gè)組件最大的加載時(shí)間,用一個(gè)倒計(jì)時(shí),每次組件加載完就清空倒計(jì)時(shí),再重新創(chuàng)建倒計(jì)時(shí)。如果加載時(shí)間超過(guò)倒計(jì)時(shí)的時(shí)間,則這個(gè)組件不是首屏的時(shí)間計(jì)算之內(nèi)。

什么作為頁(yè)面加載完成的依據(jù)?倒計(jì)時(shí)結(jié)束就不再獲取組件的加載完成時(shí)間,得出來(lái)的頁(yè)面最后加載的組件的時(shí)間就是首屏結(jié)束的時(shí)間

上代碼:

import Vue from 'vue';
class whiteScreen {
    constructor({ safeTime = 3000 } = {}) {
        // 設(shè)置組件最大加載時(shí)間
        this.safeTime = safeTime;
        // 其他...
        Vue.mixin({
            /** 
            * 注意這里要用到mounted而不是created,因?yàn)槲覀円涗洶灼恋臅r(shí)間
            * 所以是用戶看到界面的時(shí)刻,用mounted比created更加適合,具體看 vue 組件的生命周期 
            * 另外vue在組件和子組件加載機(jī)制。created和mounted執(zhí)行時(shí)機(jī)也存在區(qū)別 
            */
            mounted() {
            // 如果不是正在加載中,則返回
            if (!_this.isLoading()) return;
            // 獲取組件標(biāo)簽
            const name = this.$options.name || this.$options._componentTag;
            // 如果該組件已經(jīng)加載過(guò),則不用再記錄
            if (_this.isCompLoaded(name)) return;
            this.$nextTick(() => {
                if (name) {
                    _this.push({
                    name: name,
                    // 記錄當(dāng)前組件加載成功的時(shí)間
                    time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
             });
            }
           });
          }
      });
    }
    isLoading() {
        return this.loading;
    }
    setLoading(value) {
      this.loading = value;
      if (!this.isLoading()) {
        const data = [...this.times];
        const startTime = this.startTime;
        // TODO: 上傳埋點(diǎn)
        console.log({
          data,
          startTime,
        });
      }
    }
    createCountDown() {
      window.clearTimeout(this.countTime);
      this.countTime = window.setTimeout(() => {
        this.setLoading(false);
      }, this.safeTime);
    }
    isCompLoaded(name) {
      if (!this.isLoadedComp[name]) {
        this.isLoadedComp[name] = true;
        return false;
      }
      return this.isLoadedComp[name];
    }
    push(item) {
      // 重新創(chuàng)建定時(shí)器
      this.createCountDown();
      this.times.push(item);
    }
}

這種方式是存在一定缺陷,雖然 safeTime 是可以傳進(jìn)來(lái)的,但是這個(gè)值不好設(shè)置,這里我們默認(rèn)3秒,如果組件需要加載3秒,或者3秒內(nèi)沒(méi)有組件加載,我們視為首屏加載結(jié)束(注意:這里的倒計(jì)時(shí)不是從 window.onload 開(kāi)始的,而且在第一個(gè)組件mounted完成的時(shí)候開(kāi)始,所以算的組件加載完成到下一個(gè)組件加載完成是否超過(guò)3秒)

怎么兼容骨架屏完成的情況

這里我們可以取巧,骨架屏組件修改如下:

<div>
    <span v-if="isOpen">我是骨架屏</span>
    <span v-else> 
    // 這里可以寫(xiě)成空樣式的組件 
    <skeleton-loaded></skeleton-loaded>
    <slot></slot>
    </span>
</div> 
// skeleton-loaded 
<span></span>

當(dāng)骨架屏結(jié)束的時(shí)候,出現(xiàn)一個(gè) skeleton-loaded 組件,那么這個(gè)組件會(huì)走mounted。被我們監(jiān)聽(tīng)到,最后可以得到骨架屏的加載接觸的情況

// 這個(gè)就是骨架屏組件加載結(jié)束的時(shí)間
const skeletonLoadedTime = this.times.find(item =&gt; item.name === 'skeleton-loaded').time 

當(dāng)然,這只是個(gè)例子,現(xiàn)實(shí)可以隨你自己去發(fā)揮,確定什么是代表首屏結(jié)束的標(biāo)志,好比我的真實(shí)業(yè)務(wù)情況,就是很簡(jiǎn)單,找到 element-ui 的 el-table 就可以了

// 這個(gè)就是 el-table 組件加載結(jié)束的時(shí)間
const elTableLoadedTime = this.times.find(item =&gt; item.name === 'el-table').time

結(jié)論

通過(guò)上面和結(jié)合perforemance,我們可以得出下面的時(shí)間:

  • 所有組件加載的時(shí)間times
  • 首屏的時(shí)間(刷新開(kāi)始到最后一個(gè)時(shí)間結(jié)束):times[times.length - 1](最后一個(gè)組件的加載時(shí)間) - perforemance.timing.navigationStart(unload上一個(gè)文檔的時(shí)間節(jié)點(diǎn))
  • 框架加載時(shí)間的時(shí)間:times[0](第一個(gè)組件加載的時(shí)間) - perforemance.timing.responseEnd(瀏覽器從服務(wù)器收到HTTP請(qǐng)求返回的最后一個(gè)字節(jié)的時(shí)間)
  • 加載js資源所需要的時(shí)間:perforemance.timing.responseEnd(瀏覽器從服務(wù)器收到HTTP請(qǐng)求返回的最后一個(gè)字節(jié)的時(shí)間) - perforemance.timing.requestStart(瀏覽器向服務(wù)器發(fā)起HTTP請(qǐng)求(包含緩存,本地資源))

其實(shí)文中的思路其實(shí)特別簡(jiǎn)單,而且可以根據(jù)自己的需求來(lái)定制,兼容各種情況,有疑問(wèn)可以在評(píng)論區(qū)提出。

謝謝觀看,最后祝大家上線沒(méi)bug,更多關(guān)于Vue首屏?xí)r間指標(biāo)采集的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • axios攔截器工作方式及原理源碼解析

    axios攔截器工作方式及原理源碼解析

    這篇文章主要為大家介紹了axios攔截器工作原理源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • vue2.x中的provide和inject用法小結(jié)

    vue2.x中的provide和inject用法小結(jié)

    這篇文章主要介紹了vue2.x中的provide和inject用法小結(jié),本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-12-12
  • 關(guān)于Vue3中的響應(yīng)式原理

    關(guān)于Vue3中的響應(yīng)式原理

    這篇文章主要介紹了關(guān)于Vue3中的響應(yīng)式原理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • UniApp在Vue3下使用setup語(yǔ)法糖創(chuàng)建和使用自定義組件的操作方法

    UniApp在Vue3下使用setup語(yǔ)法糖創(chuàng)建和使用自定義組件的操作方法

    通過(guò)defineProps定義屬性,defineEmits定義事件,computed創(chuàng)建計(jì)算屬性,emitEvent方法觸發(fā)事件,在其他組件中導(dǎo)入并使用這些自定義組件,傳遞屬性和監(jiān)聽(tīng)事件,實(shí)現(xiàn)組件的復(fù)用性和可維護(hù)性,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • v-for中動(dòng)態(tài)校驗(yàn)el-form表單項(xiàng)的實(shí)踐

    v-for中動(dòng)態(tài)校驗(yàn)el-form表單項(xiàng)的實(shí)踐

    在項(xiàng)目開(kāi)發(fā)中,我們經(jīng)常會(huì)遇到表單保存的功能,本文主要介紹了v-for中動(dòng)態(tài)校驗(yàn)el-form表單項(xiàng)的實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧<BR>
    2022-05-05
  • 實(shí)例講解Vue.js中router傳參

    實(shí)例講解Vue.js中router傳參

    本篇文章通過(guò)實(shí)例給大家分析了Vue.js中router傳參的相關(guān)知識(shí)點(diǎn),對(duì)此有興趣的朋友參考學(xué)習(xí)下。
    2018-04-04
  • 詳解vue-meta如何讓你更優(yōu)雅的管理頭部標(biāo)簽

    詳解vue-meta如何讓你更優(yōu)雅的管理頭部標(biāo)簽

    這篇文章主要介紹了詳解vue-meta如何讓你更優(yōu)雅的管理頭部標(biāo)簽,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • axios異步提交表單數(shù)據(jù)的幾種方法

    axios異步提交表單數(shù)據(jù)的幾種方法

    這篇文章主要給大家介紹了關(guān)于axios異步提交表單數(shù)據(jù)的幾種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位大家學(xué)習(xí)或者使用axios具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • 封裝Vue Element的table表格組件的示例詳解

    封裝Vue Element的table表格組件的示例詳解

    這篇文章主要介紹了封裝Vue Element的table表格組件的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2020-08-08
  • antd的選擇框如何增加tab選中的方法示例

    antd的選擇框如何增加tab選中的方法示例

    這篇文章主要為大家介紹了antd的選擇框如何增加tab選中的方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08

最新評(píng)論

县级市| 门头沟区| 宾阳县| 湄潭县| 江阴市| 新平| 莒南县| 望谟县| 宁南县| 杨浦区| 巴林右旗| 甘南县| 临颍县| 叙永县| 灵川县| 上杭县| 邮箱| 白朗县| 汉川市| 霍林郭勒市| 津南区| 苍梧县| 洪泽县| 喜德县| 宝清县| 嵩明县| 永福县| 鹿泉市| 宝丰县| 鸡泽县| 蒙城县| 嵩明县| 丽水市| 沧州市| 句容市| 日喀则市| 桐柏县| 洛扎县| 珲春市| 汝南县| 长海县|