白屏时间指的是:页面开始显示内容的时间。
也就是:浏览器显示第一个字符或者元素的时间图片
怎么算?<head> <title>Document</title> </head> <script type="text/javascript"> // 白屏时间结束点 var firstPaint = Date.now() var start = performance.timing.navigationStart console.log(firstPaint - start) </script>.浏览器不支持performance.timing
<head> <title>Document</title> <script type="text/javascript"> window.start = Date.now(); </script> </head> <script type="text/javascript"> // 白屏时间结束点 var firstPaint = Date.now() console.log(firstPaint - window.start) </script>首屏时间
<body> <div> <div>1</div> <div>2</div> </div> </body>以上DOM结构的分数为:
1.5 + 2 + 2.5 + 2.5 = 8.5(分)
<!DOCTYPE html> <html lang="en"> <head> <title>堆代码 duidaima.com </title> </head> <body> <div> <div> <div>1</div> <div>2</div> </div> <div>3</div> <div>4</div> </div> <ul id="ulbox"></ul> </body> <script src="./computed.js"></script> <script src="./request.js"></script> </html>computed.js:计算首屏时间的文件
const observerData = [] let observer = new MutationObserver(() => { // 计算每次DOM修改时,距离页面刚开始加载的时间 const start = window.performance.timing.navigationStart const time = new Date().getTime() - start const body = document.querySelector('body') const score = computedScore(body, 1) // 加到数组 observerData 中 observerData.push({ score, time }) }) observer.observe( document, { childList: true, subtree: true } ) function computedScore(element, layer) { let score = 0 const tagName = element.tagName // 排除这些标签的情况 if ( tagName !== 'SCRIPT' && tagName !== 'STYLE' && tagName !== 'META' && tagName !== 'HEAD' ) { const children = element.children if (children && children.length) { // 递归计算分数 for (let i = 0; i < children.length; i++) { score += computedScore(children[i], layer + 1) } } score += 1 + 0.5 * layer } return score }request.js:模拟请求修改DOM
// 模拟请求列表 const requestList = () => { return new Promise((resolve) => { setTimeout(() => { resolve( [1, 2, 3, 4, 5, 6, 7, 8, 9 ] ) }, 1000) }) } const ulbox = document.getElementById('ulbox') // 模拟请求数据渲染列表 const renderList = async () => { const list = await requestList() const fragment = document.createDocumentFragment() for (let i = 0; i < list.length; i++) { const li = document.createElement('li') li.innerText = list[i] fragment.appendChild(li) } ulbox.appendChild(fragment) } // 模拟对列表进行轻微修改 const addList = async () => { const li = document.createElement('li') li.innerText = '加上去' ulbox.appendChild(li) } (async () => { // 模拟请求数据渲染列表 await renderList() // 模拟对列表进行轻微修改 addList() })()observerData
const observerData = [] let observer = new MutationObserver(() => { // 计算每次DOM修改时,距离页面刚开始加载的时间 const start = window.performance.timing.navigationStart const time = new Date().getTime() - start const body = document.querySelector('body') const score = computedScore(body, 1) observerData.push({ score, time }) // complete时去调用 unmountObserver if (document.readyState === 'complete') { // 只计算10秒内渲染时间 unmountObserver(10000) } }) observer.observe( document, { childList: true, subtree: true } ) function computedScore(element, layer) { let score = 0 const tagName = element.tagName // 排除这些标签的情况 if ( tagName !== 'SCRIPT' && tagName !== 'STYLE' && tagName !== 'META' && tagName !== 'HEAD' ) { const children = element.children if (children && children.length) { // 递归计算分数 for (let i = 0; i < children.length; i++) { score += computedScore(children[i], layer + 1) } } score += 1 + 0.5 * layer } return score } // 计算首屏时间 function getFirstScreenTime() { let data = null for (let i = 1; i < observerData.length; i++) { // 计算幅度 const differ = observerData[i].score - observerData[i - 1].score // 取最大幅度,记录对应时间 if (!data || data.rate <= differ) { data = { time: observerData[i].time, rate: differ } } } return data } let timer = null function unmountObserver(delay) { if (timer) return timer = setTimeout(() => { // 输出首屏时间 console.log(getFirstScreenTime()) // 终止MutationObserver的监控 observer.disconnect() observer = null clearTimeout(timer) }, delay) }计算出首屏时间1020ms