diff --git a/src/config/define.ts b/src/config/define.ts index de08dbe..9d86db4 100644 --- a/src/config/define.ts +++ b/src/config/define.ts @@ -3,6 +3,11 @@ import { SpotType } from '../define'; import { StabilityType, RuntimeErrorSpot, ResourceLoadErrorSpot, PromiseRejectionSpot, BlankScreenSpot, XHRSpot, FetchSpot } from '../microspot/stability/define'; import { ExperienceType, FirstPaintSpot, FirstContentfulPaintSpot, LargestContentfulPaintSpot, FirstInputDelaySpot, CumulativeLayoutShiftSpot, LongTaskSpot } from '../microspot/experience/define'; +/** 上报函数定义 */ +type StabilitySpot = RuntimeErrorSpot | ResourceLoadErrorSpot | PromiseRejectionSpot | BlankScreenSpot | XHRSpot | FetchSpot; +type ExperienceSpot = FirstPaintSpot | FirstContentfulPaintSpot | LargestContentfulPaintSpot | FirstInputDelaySpot | CumulativeLayoutShiftSpot | LongTaskSpot; +export type Send = (spot: StabilitySpot | ExperienceSpot, options: DefaultIndexOption) => void;; + /** 配置 config 定义 */ export type IndexType = string | StabilityType | ExperienceType; export type IndexOption = { type: IndexType, /** 采样率 0 - 1 */ sampling: number } @@ -14,7 +19,7 @@ export type Tracker = (string | TrackerOption)[]; export interface Config { tracker: Tracker; lastEvent?: boolean; - send?: (spot: any) => void; + send?: Send; } /** 默认配置的定义 */ @@ -25,10 +30,6 @@ export type DefaultIndex = DefaultIndexOption[]; export type DefaultTrackerOption = { type: SpotType, index: DefaultIndex } export type DefaultTracker = DefaultTrackerOption[]; -type StabilitySpot = RuntimeErrorSpot | ResourceLoadErrorSpot | PromiseRejectionSpot | BlankScreenSpot | XHRSpot | FetchSpot; -type ExperienceSpot = FirstPaintSpot | FirstContentfulPaintSpot | LargestContentfulPaintSpot | FirstInputDelaySpot | CumulativeLayoutShiftSpot | LongTaskSpot; -export type Send = (spot: StabilitySpot | ExperienceSpot, options: DefaultIndexOption) => void;; - export interface DefaultConfig { tracker: DefaultTracker; lastEvent: boolean; diff --git a/src/config/microspot.config.ts b/src/config/microspot.config.ts index 01035e5..d949e63 100644 --- a/src/config/microspot.config.ts +++ b/src/config/microspot.config.ts @@ -5,7 +5,6 @@ import { DefaultConfig } from './define'; import { getIndex } from './utils/default'; import { SpotType } from '../define'; - import { gifReport } from '../utils/gifReport'; const config: DefaultConfig = { diff --git a/src/index.ts b/src/index.ts index 1884514..9b4fa95 100644 --- a/src/index.ts +++ b/src/index.ts @@ -36,5 +36,8 @@ configure({ }, 'EXPERIENCE' ], - lastEvent: true + lastEvent: true, + send: (spot) => { + console.log('覆盖上传', spot) + } }); \ No newline at end of file diff --git a/src/microspot/experience/define.ts b/src/microspot/experience/define.ts index 430f4aa..127f89b 100644 --- a/src/microspot/experience/define.ts +++ b/src/microspot/experience/define.ts @@ -6,7 +6,8 @@ export enum ExperienceType { LARGEST_CONTENTFUL_PAINT = 'LARGEST_CONTENTFUL_PAINT', FIRST_INPUT_DELAY = 'FIRST_INPUT_DELAY', CUMULATIVE_LAYOUT_SHIFT = 'CUMULATIVE_LAYOUT_SHIFT', - LONG_TASK = 'LONG_TASK' + LONG_TASK = 'LONG_TASK', + TIMING = 'TIMING' } export interface ExperienceSpot extends Spot { @@ -55,3 +56,34 @@ export interface LongTaskSpot extends ExperienceSpot { duration: string; selector: string; } + + +/** 页面耗时上报 */ +export interface TimingSpot extends ExperienceSpot { + /** 性能元数据 */ + raw: PerformanceNavigationTiming; + /** 页面加载总耗时 */ + loadTiming: string; + /** DNS 解析耗时 */ + dnsTiming: string; + /** TCP 连接耗时 */ + tcpTiming: string; + /** SSL 连接耗时 */ + sslTiming: string; + /** 网路请求耗时 */ + requestTiming: string; + /** 数据请求耗时 */ + responseTiming: string; + /** DOM 解析耗时 */ + domTiming: string; + /** 资源加载耗时 */ + resourceTiming: string; + /** 首包耗时 */ + firstPacketTiming: string; + /** 页面渲染耗时 */ + renderTiming: string; + /** HTML 加载完时间 */ + htmlTiming: string; + /** 首次可交互时间 */ + firstInteractiveTiming: string; +} \ No newline at end of file diff --git a/src/microspot/experience/tracker/common/firstContentfulPaint.ts b/src/microspot/experience/tracker/common/firstContentfulPaint.ts index 147395b..901ea32 100644 --- a/src/microspot/experience/tracker/common/firstContentfulPaint.ts +++ b/src/microspot/experience/tracker/common/firstContentfulPaint.ts @@ -11,9 +11,9 @@ function injectFCPTracker(props: Pick) { if (!idx) return; const observer = new PerformanceObserver((entries, observer) => { - const firstContentPaint = entries.getEntriesByName('first-contentful-paint'); - const startTime = firstContentPaint[0].startTime; - const duration = firstContentPaint[0].duration; + const firstContentPaint = entries.getEntriesByName('first-contentful-paint')[0]; + const startTime = firstContentPaint.startTime; + const duration = firstContentPaint.duration; const spot: FirstContentfulPaintSpot = { type: SpotType.EXPERIENCE, diff --git a/src/microspot/experience/tracker/common/firstPaint.ts b/src/microspot/experience/tracker/common/firstPaint.ts index bc5f1c8..9574aca 100644 --- a/src/microspot/experience/tracker/common/firstPaint.ts +++ b/src/microspot/experience/tracker/common/firstPaint.ts @@ -11,9 +11,9 @@ function injectFPTracker(props: Pick) { if (!idx) return; const observer = new PerformanceObserver((entries, observer) => { - const firstPaint = entries.getEntriesByName('first-paint'); - const startTime = firstPaint[0].startTime; - const duration = firstPaint[0].duration; + const firstPaint = entries.getEntriesByName('first-paint')[0]; + const startTime = firstPaint.startTime; + const duration = firstPaint.duration; const spot: FirstPaintSpot = { type: SpotType.EXPERIENCE, diff --git a/src/microspot/experience/tracker/common/index.ts b/src/microspot/experience/tracker/common/index.ts index d25cd93..2da810d 100644 --- a/src/microspot/experience/tracker/common/index.ts +++ b/src/microspot/experience/tracker/common/index.ts @@ -2,7 +2,9 @@ import { SpotOption } from '../../../../define'; import { injectFPTracker } from './firstPaint'; import { injectFCPTracker } from './firstContentfulPaint'; -import { injectLTTracker } from './longTask' +import { injectLTTracker } from './longTask'; + +import { injectTimingTracker } from './timing'; function injectCommonTracker(props: Pick) { /** FP */ @@ -13,6 +15,9 @@ function injectCommonTracker(props: Pick) { /** 长任务*/ injectLTTracker.call(null, props); + + /** 各个阶段耗时 */ + injectTimingTracker(); } export { diff --git a/src/microspot/experience/tracker/common/timing.ts b/src/microspot/experience/tracker/common/timing.ts new file mode 100644 index 0000000..f698831 --- /dev/null +++ b/src/microspot/experience/tracker/common/timing.ts @@ -0,0 +1,35 @@ +import { SpotType } from '../../../../define'; +import { ExperienceType, TimingSpot } from '../../define'; +function injectTimingTracker() { + const observer = new PerformanceObserver((entries, observer) => { + console.log('entries', entries.getEntries()) + const navigationTiming = entries.getEntries()[0] as PerformanceNavigationTiming; + + const spot: TimingSpot = { + type: SpotType.EXPERIENCE, + subType: ExperienceType.TIMING, + raw: navigationTiming, + loadTiming: `${navigationTiming.loadEventEnd - navigationTiming.startTime}`, + dnsTiming: `${navigationTiming.domainLookupEnd - navigationTiming.domainLookupStart}`, + tcpTiming: `${navigationTiming.connectEnd - navigationTiming.connectStart}`, + sslTiming: `${location.protocol === 'https:' ? navigationTiming.connectEnd - navigationTiming.secureConnectionStart : '0'}`, + requestTiming: `${navigationTiming.responseStart - navigationTiming.requestStart}`, + responseTiming: `${navigationTiming.responseEnd - navigationTiming.responseStart}`, + domTiming: `${navigationTiming.domContentLoadedEventEnd - navigationTiming.responseEnd}`, + resourceTiming: `${navigationTiming.loadEventEnd - navigationTiming.domContentLoadedEventEnd}`, + firstPacketTiming: `${navigationTiming.responseStart - navigationTiming.startTime}`, + renderTiming: `${navigationTiming.loadEventEnd - navigationTiming.responseEnd}`, + htmlTiming: `${navigationTiming.responseEnd - navigationTiming.startTime}`, + firstInteractiveTiming: `${navigationTiming.domInteractive - navigationTiming.startTime}`, + + } + + console.log(spot, 'navigationTiming') + }); + + observer.observe({ entryTypes: ['navigation'] }); +} + +export { + injectTimingTracker +} \ No newline at end of file