performance-event-timing-polyfill
Version:
Provide a polyfill for the PerformanceEventTiming interface
2 lines (1 loc) • 5.86 kB
JavaScript
const e={pointer:["pointerdown","pointerup","click"],keyboard:["keydown","keyup"]},t=["click","auxclick","keyup","pointercancel","contextmenu"],n=[],r={},o=new MessageChannel,i=["pointerdown","mousedown","pointerup","mouseup","click","auxclick","contextmenu","pointercancel","keydown","keypress","keyup"],s={},a=new Set;let c=!1,p=0,f=[],l=0,u=0,d=null,h=performance.now();const y=e=>{n.push(e)},m=e=>{window.addEventListener(e,(t=>{const n=performance.now();switch(e){case"pointerdown":case"keydown":l++}if(a.has(l))return;const r={startTime:n,duration:0,target:t.target,eventType:t.type,eventTime:t.timeStamp,interactionId:l,paintEnd:0,endTime:0,inputDelay:n-t.timeStamp,processingDuration:0,presentationDelay:0};g(t,r),w(r)}),!0)},v=()=>{h=performance.now(),requestAnimationFrame(v)},w=e=>{clearTimeout(p);const t=r[h];if(t||(r[h]=[]),r[h].push(e),t)return;const n=h;requestAnimationFrame((()=>{const e=h;T((t=>{const o=t-e;r[n].forEach((e=>{e.presentationDelay=o,e.paintEnd=t})),p=setTimeout(E,20),delete r[n]}))}))},T=e=>{let t=!1;requestAnimationFrame((n=>{t||(e(h,"animationFrame"),t=!0)})),o.port2.postMessage((e=>(s[u]=e,u++))((n=>{t||(e(performance.now(),"channelMessage"),t=!0)}))),d=n=>{t||(e(performance.now(),"eventFired"),t=!0)}},g=(e,t)=>{d&&d(e);const n=e.type;new Promise((e=>{T((t=>{e({evName:n,timeStamp:t})}))})).then((({timeStamp:e})=>{const n=e-t.startTime;t.duration=n,t.endTime=e,t.processingDuration=n,f.push(t)}))},E=()=>{if(!f.length)return;const e=(()=>{if(!f.length)return[];const e={};return f.forEach((t=>{e[t.interactionId]||(e[t.interactionId]=[]),e[t.interactionId].push(t)})),Object.values(e).filter((e=>e[e.length-1].paintEnd>0&&t.includes(e[e.length-1].eventType))).flat()})();if(e.length){n.forEach((t=>{t(e)}));for(const t of e)a.add(t.interactionId),f.splice(f.indexOf(t),1)}};var b=this&&this.__classPrivateFieldSet||function(e,t,n,r,o){if("m"===r)throw new TypeError("Private method is not writable");if("a"===r&&!o)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!o:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===r?o.call(e,n):o?o.value=n:t.set(e,n),n},O=this&&this.__classPrivateFieldGet||function(e,t,n,r){if("a"===n&&!r)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?r:"a"===n?r.call(e):r?r.value:t.get(e)};let k=null;const P=["event","first-input"],x="PerformanceEventTiming"in self&&"interactionId"in PerformanceEventTiming.prototype,I=()=>{var t,n,r,a,p;if((()=>{if(!c){c=!0,o.port1.onmessage=e=>{s[e.data](e),delete s[e.data]};for(const e of i)m(e);document.addEventListener("click",(()=>{}),!0),requestAnimationFrame(v)}})(),!("PerformanceObserver"in self))return;if(!window.forceEventTimingPolyfill&&x)return;class f{static fromObject(e){const t=new f;return Object.assign(t,e),t}}f.prototype.startTime=0,f.prototype.duration=0,f.prototype.entryType="event",f.prototype.name="event",f.prototype.cancelable=!0,f.prototype.interactionId=0,f.prototype.processingEnd=0,f.prototype.processingStart=0,f.prototype.target=null,f.prototype.toJSON=function(){const e={};for(const t of Object.keys(this))e[t]=this[t];return JSON.stringify(e)},f.prototype.intoFirstInputEntry=function(){const e={};for(const t of Object.keys(this))e[t]=this[t];return e.entryType="first-input",f.fromObject(e)},self.PerformanceEventTiming=f;class l{constructor(e,n){t.set(this,void 0),b(this,t,e.filter((e=>e.duration>=(n||16))),"f")}getEntries(){return O(this,t,"f")}getEntriesByName(e,n){return O(this,t,"f").filter((t=>t.name===e&&(!n||t.entryType===n)))}getEntriesByType(e){return O(this,t,"f").filter((t=>t.entryType===e))}}t=new WeakMap;class u extends PerformanceObserver{constructor(e){super(e),p.set(this,void 0),this.threshold=104,b(this,p,e,"f")}observe(e){null==e.entryTypes||null==e.durationThreshold&&null==e.buffered&&null==e.type||(e.entryTypes=void 0);let t=!1;if(!e.entryTypes||(e.entryTypes.some((e=>-1==P.indexOf(e)))&&(super.observe(e),t=!0),e.entryTypes.some((e=>P.indexOf(e)>-1))))if(e.type&&-1!=P.indexOf(e.type.toLowerCase()))if(window.forceEventTimingPolyfill||!x||t){if(h.push([O(this,p,"f"),this]),null==e.durationThreshold||e.entryTypes||(this.threshold=Math.max(e.durationThreshold,16)),e.buffered&&!e.entryTypes){if("first-input"==e.type)return void(k&&O(this,p,"f").call(this,new l([k],this.threshold),this));O(this,p,"f").call(this,new l(d,this.threshold),this)}}else super.observe(e);else super.observe(e)}disconnect(){super.disconnect();const e=h.indexOf([O(this,p,"f"),this]);-1!==e&&h.splice(e,1)}static get supportedEntryTypes(){return null==O(n,n,"f",a)&&(b(n,n,Array.from(O(n,n,"f",r).supportedEntryTypes),"f",a),-1==O(n,n,"f",a).indexOf("event")&&(O(n,n,"f",a).push("event"),O(n,n,"f",a).push("first-input"))),O(n,n,"f",a)}}n=u,p=new WeakMap,r={value:PerformanceObserver},a={value:void 0},self.PerformanceObserver=u;const d=[],h=[],w=e=>{const t=e%8;return e+=t>0?8-(8-t<4?-(8-t):8-t):0};y((t=>{const n={},r=Object.values(e).flat();t.forEach((e=>{n[e.interactionId]||(n[e.interactionId]=[]),n[e.interactionId].push(f.fromObject({startTime:e.eventTime,duration:w(Math.round(e.paintEnd-e.eventTime)),interactionId:r.indexOf(e.eventType)>-1?e.interactionId:0,processingStart:e.startTime,processingEnd:e.startTime+e.processingDuration,entryType:"event",name:e.eventType,target:e.target}))}));const o=Object.values(n).flat();d.push(...o);for(const[e,t]of h){const n=new l(o,t.threshold);n.getEntries().length&&e(n,t)}if(!k&&d.length){k=d[0].intoFirstInputEntry();for(const[e,t]of h){const n=new l([k],t.threshold);n.getEntries().length&&e(n,t)}}}))};I();export{I as initPolyfill,y as onInteraction};