國(guó)外專門做童裝的網(wǎng)站網(wǎng)絡(luò)營(yíng)銷的概念和含義
1. 用戶體驗(yàn)優(yōu)化
2. Web Vitals提取了幾個(gè)核心網(wǎng)絡(luò)指標(biāo)
哇一頭死 FCL 三大指標(biāo) FID被 INP干點(diǎn)
- Largest Contentful Paint (LCP):最大內(nèi)容繪制 衡量加載性能。 為了提供良好的用戶體驗(yàn),LCP 必須在網(wǎng)頁(yè)首次開(kāi)始加載后的 2.5 秒內(nèi)發(fā)生。
- Interaction to Next Paint (INP):替代首次輸入延遲 (FID) 衡量互動(dòng)。為了提供良好的用戶體驗(yàn),網(wǎng)頁(yè)的 INP 不得超過(guò) 200 毫秒。INP測(cè)量的是從用戶與網(wǎng)頁(yè)發(fā)生交互那一刻起到瀏覽器完成與該交互相關(guān)的下一個(gè)渲染幀(Paint)的時(shí)間間隔。
-
- INP 是 First Input Delay (FID) 的繼任指標(biāo)。雖然兩者都是響應(yīng)能力指標(biāo),但 FID 僅測(cè)量了頁(yè)面上首次互動(dòng)的輸入延遲。INP 通過(guò)考慮所有頁(yè)面互動(dòng)(從輸入延遲到運(yùn)行事件處理程序所需的時(shí)間,再到瀏覽器繪制下一幀)來(lái)改進(jìn) FID。
- 這些差異意味著 INP 和 FID 是不同類型的響應(yīng)能力指標(biāo)。FID 是一項(xiàng)旨在評(píng)估網(wǎng)頁(yè)對(duì)用戶的首次展示的加載響應(yīng)能力指標(biāo),而無(wú)論網(wǎng)頁(yè)互動(dòng)的生命周期是何時(shí)發(fā)生,INP 都是更可靠的整體響應(yīng)能力指標(biāo)。
- Cumulative Layout Shift (CLS):累計(jì)布局偏移,衡量視覺(jué)穩(wěn)定性。為了提供良好的用戶體驗(yàn),必須將 CLS 保持在 0.1. 或更低。
- 首次內(nèi)容繪制 (FCP):用于衡量從網(wǎng)頁(yè)開(kāi)始加載到網(wǎng)頁(yè)任何部分的內(nèi)容呈現(xiàn)在屏幕上所用的時(shí)間。(lab,字段)
- 總阻塞時(shí)間 (TBT):測(cè)量 FCP 和 TTI 之間的總時(shí)間,在此期間主線程處于阻塞狀態(tài)的時(shí)間足夠長(zhǎng),足以阻止輸入響應(yīng)。(實(shí)驗(yàn))
- 首字節(jié)時(shí)間 (TTFB):測(cè)量網(wǎng)絡(luò)使用資源的第一個(gè)字節(jié)響應(yīng)用戶請(qǐng)求所需的時(shí)間。(lab,字段)
?
3. 測(cè)量工具
野外工具
- Chrome 用戶體驗(yàn)報(bào)告
- PageSpeed Insights
- Search Console(“核心網(wǎng)頁(yè)指標(biāo)”報(bào)告)
- web-vitalsJavaScript 庫(kù)
實(shí)驗(yàn)工具
- Chrome 開(kāi)發(fā)者工具
- 燈塔
- PageSpeed Insights
- WebPageTest
4. 如何優(yōu)化FCP
- 移除阻塞渲染的資源
- 縮減 CSS 大小
- 移除未使用的 CSS
- 移除未使用的 JavaScript
- 預(yù)先連接到所需的源
- 縮短服務(wù)器響應(yīng)時(shí)間 (TTFB)
- 避免多次網(wǎng)頁(yè)重定向
- 預(yù)加載密鑰請(qǐng)求
- 避免網(wǎng)絡(luò)負(fù)載龐大
- 采用高效的緩存政策提供靜態(tài)資源
- 避免 DOM 規(guī)模過(guò)大
- 最大限度地縮短關(guān)鍵請(qǐng)求深度
- 確保文本在網(wǎng)頁(yè)字體加載期間保持可見(jiàn)狀態(tài)
- 盡量減少請(qǐng)求數(shù)量,減少傳輸大小
5. 如何優(yōu)化 INP
- 識(shí)別并減少輸入延遲
-
- 啟動(dòng)期間腳本評(píng)估和耗時(shí)較長(zhǎng)的任務(wù)之間的關(guān)系
- 優(yōu)化事件回調(diào)
-
- 頻繁讓出主線程
- 避免布局抖動(dòng)
- 最大限度減少展示延遲時(shí)間
-
- 遵從請(qǐng)求,以便更快執(zhí)行渲染工作
- 盡可能減小 DOM 大小
- 使用 content-visibility 延遲渲染屏幕外元素
- 注意使用 JavaScript 呈現(xiàn) HTML 時(shí)的性能開(kāi)銷
6. 如何優(yōu)化CLS
- 沒(méi)有尺寸的圖片
- 廣告、嵌入內(nèi)容和其他延遲加載的內(nèi)容預(yù)留空間
- 動(dòng)畫(huà)
- 網(wǎng)絡(luò)字體(使用無(wú)樣式文本的 flash、將后備字體與網(wǎng)頁(yè)字體交換)
7. 純 js 如何檢查當(dāng)前頁(yè)面是否白屏
檢測(cè)當(dāng)前頁(yè)面是否出現(xiàn)白屏現(xiàn)象,可以采用以下幾種純 JavaScript 方法:
- 利用
window.onload
或DOMContentLoaded
事件:
當(dāng)頁(yè)面加載完成或初始HTML文檔解析完畢時(shí),觸發(fā)相關(guān)事件,然后檢查頁(yè)面是否為空白。這可以通過(guò)檢查頁(yè)面上是否存在非空白內(nèi)容來(lái)實(shí)現(xiàn),比如檢查是否有可見(jiàn)的非空DOM元素或者特定類別的元素。
document.addEventListener('DOMContentLoaded', function() {const isEmpty = checkIfPageIsEmpty();if (isEmpty) {handleWhiteScreen(); // 定義處理白屏的函數(shù)}
});function checkIfPageIsEmpty() {// 檢查頁(yè)面中是否存在非空白內(nèi)容,如可見(jiàn)的非空DOM元素// 這里僅作為示例,實(shí)際邏輯可能需要更精細(xì)的判斷return !document.querySelector(':not(script):not(style):not(noscript)');
}function handleWhiteScreen() {console.error('Page appears to be blank.');// 可以在此處添加具體的白屏處理邏輯,如上報(bào)異常、顯示提示信息等
}
- 利用
requestAnimationFrame
循環(huán)檢測(cè):
如果擔(dān)心單純依賴DOMContentLoaded
事件可能無(wú)法捕捉到某些動(dòng)態(tài)加載內(nèi)容導(dǎo)致的白屏情況,可以使用requestAnimationFrame
循環(huán)檢查頁(yè)面視覺(jué)上的空白狀態(tài)。這種方法尤其適用于那些依賴異步加載內(nèi)容填充頁(yè)面的場(chǎng)景。
function detectWhiteScreen() {const bodyRect = document.body.getBoundingClientRect();const bodyIsWhite = bodyRect.width > 0 && bodyRect.height > 0 &&window.getComputedStyle(document.body).backgroundColor === 'white';if (bodyIsWhite) {console.error('Page appears to be visually blank.');// 可能需要停止循環(huán)檢測(cè)并執(zhí)行處理邏輯} else {// 頁(yè)面非白屏,繼續(xù)監(jiān)測(cè)下一幀requestAnimationFrame(detectWhiteScreen);}
}// 在頁(yè)面加載完成后開(kāi)始檢測(cè)
document.addEventListener('DOMContentLoaded', function() {requestAnimationFrame(detectWhiteScreen);
});
- 使用Canvas或
getImageData
進(jìn)行像素級(jí)檢測(cè):
對(duì)于更為嚴(yán)格的白屏檢測(cè),可以利用canvas
元素將頁(yè)面內(nèi)容繪制到畫(huà)布上,然后通過(guò)getImageData
獲取像素?cái)?shù)據(jù),檢查其中白色像素的比例。這種方法較為復(fù)雜,且可能受到跨域限制,但對(duì)于需要精確識(shí)別頁(yè)面是否完全空白的應(yīng)用場(chǎng)景可能有幫助。
async function checkPageForBlankness() {const canvas = document.createElement('canvas');const ctx = canvas.getContext('2d');// 設(shè)置canvas大小與視口一致canvas.width = document.documentElement.clientWidth;canvas.height = document.documentElement.clientHeight;// 將整個(gè)頁(yè)面內(nèi)容繪制到canvas上ctx.drawWindow(window, 0, 0, canvas.width, canvas.height, 'rgb(255,255,255)', false);// 獲取像素?cái)?shù)據(jù)const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);const data = imageData.data;let whitePixels = 0;for (let i = 0; i < data.length; i += 4) {// 檢查是否為白色像素(通常為R=G=B=255,A不為0)if (data[i] === 255 && data[i + 1] === 255 && data[i + 2] === 255 && data[i + 3] !== 0) {whitePixels++;}}const whiteRatio = whitePixels / (data.length / 4);if (whiteRatio >= 0.95) { // 設(shè)置一個(gè)閾值判斷是否接近全白console.error('Page appears to be visually blank.');// 處理白屏邏輯}
}document.addEventListener('DOMContentLoaded', function() {// 注意:drawWindow方法需要瀏覽器提供特定權(quán)限,可能無(wú)法在所有環(huán)境下運(yùn)行// 若支持,可在此處調(diào)用checkPageForBlankness()
});
注意:上述使用canvas
和drawWindow
的方法可能需要特定的瀏覽器權(quán)限(如chrome://flags/#enable-experimental-web-platform-features
在Chrome中),并且可能不適用于所有瀏覽器環(huán)境。此外,這種方法可能因跨域問(wèn)題導(dǎo)致無(wú)法獲取到頁(yè)面內(nèi)容。
- 結(jié)合性能指標(biāo)與MutationObserver:
利用瀏覽器提供的性能指標(biāo),如First Contentful Paint
(FCP)或Largest Contentful Paint
(LCP),結(jié)合MutationObserver
來(lái)觀察頁(yè)面DOM的變化。如果這些關(guān)鍵渲染時(shí)間點(diǎn)過(guò)晚或者DOM變化不足以形成有意義的內(nèi)容,可以視為白屏。
// 監(jiān)聽(tīng)性能指標(biāo)
if ('PerformanceObserver' in window) {const observer = new PerformanceObserver((entries) => {entries.forEach((entry) => {if (entry.entryType === 'paint') {if (entry.name === 'first-contentful-paint') {const fcpTime = entry.startTime;console.log(`First Contentful Paint at ${fcpTime.toFixed(2)}ms`);if (fcpTime > someThreshold) { // 設(shè)置一個(gè)閾值判斷FCP是否過(guò)晚console.error('Possible white screen due to late FCP.');}}}});});observer.observe({ type: 'paint', buffered: true });
}// 使用MutationObserver監(jiān)測(cè)DOM變化
const targetNode = document.body;
const config = { childList: true, subtree: true };
const observer = new MutationObserver(checkForContent);function checkForContent(mutationsList) {for (const mutation of mutationsList) {if (mutation.type === 'childList') {const hasVisibleContent = !!mutation.addedNodes.find(node => node.nodeType === Node.ELEMENT_NODE && node.offsetWidth > 0 && node.offsetHeight > 0);if (!hasVisibleContent) {console.warn('DOM changes did not introduce visible content.');}}}
}observer.observe(targetNode, config);
綜上所述,根據(jù)具體需求和應(yīng)用場(chǎng)景,可以選擇合適的方法或結(jié)合多種方法來(lái)檢測(cè)當(dāng)前頁(yè)面是否白屏。請(qǐng)注意,由于瀏覽器兼容性和安全策略的差異,某些方法可能需要調(diào)整或無(wú)法在所有環(huán)境中使用。
8. 純 js 如何實(shí)現(xiàn)檢測(cè)當(dāng)前可視區(qū)域渲染完成
檢測(cè)當(dāng)前可視區(qū)域(viewport)渲染完成,通常是指確認(rèn)頁(yè)面或其某個(gè)部分(如一個(gè)復(fù)雜的子組件)已完全呈現(xiàn)在用戶視野內(nèi),并且所有相關(guān)的資源(如圖片、字體、腳本等)已經(jīng)加載完畢,動(dòng)畫(huà)效果已完成,用戶可以進(jìn)行無(wú)阻礙的交互。以下是一些使用純JavaScript實(shí)現(xiàn)可視區(qū)域渲染完成檢測(cè)的方法:
8.1. 1. 監(jiān)聽(tīng) load
事件
對(duì)于整個(gè)頁(yè)面的渲染完成,可以監(jiān)聽(tīng) window
對(duì)象的 load
事件,它會(huì)在所有資源(包括圖片、樣式表、腳本等)加載完畢后觸發(fā)。
window.addEventListener('load', function () {console.log('The entire page and its resources have finished rendering.');
});
8.2. 2. 監(jiān)聽(tīng) DOMContentLoaded
事件
如果關(guān)心的是初始HTML文檔結(jié)構(gòu)的加載和解析完成,而不是所有資源加載完畢,可以使用 DOMContentLoaded
事件。這通常發(fā)生在 load
事件之前,當(dāng)DOM樹(shù)構(gòu)建完成且可被腳本操作時(shí)觸發(fā)。
document.addEventListener('DOMContentLoaded', function () {console.log('The initial HTML document has been fully parsed and rendered.');
});
8.3. 3. 使用 IntersectionObserver
API
對(duì)于檢測(cè)特定元素是否進(jìn)入可視區(qū)域且完全渲染,可以利用 IntersectionObserver
API。它會(huì)異步觀察目標(biāo)元素與祖先元素或視口的交叉狀態(tài),并在狀態(tài)改變時(shí)觸發(fā)回調(diào)函數(shù)。設(shè)置合適的閾值(如1.0,表示完全可見(jiàn)),可以在元素完全進(jìn)入可視區(qū)域時(shí)得到通知。
function handleIntersection(entries) {entries.forEach(entry => {if (entry.isIntersecting && entry.intersectionRatio === 1) {console.log('The observed element is fully visible within the viewport.');// 停止觀察,避免重復(fù)觸發(fā)observer.unobserve(entry.target);}});
}const targetElement = document.querySelector('#your-element');
const observer = new IntersectionObserver(handleIntersection, { threshold: 1.0 });observer.observe(targetElement);
8.4. 4. 配合 requestAnimationFrame
循環(huán)檢查
對(duì)于更復(fù)雜的場(chǎng)景,比如需要確保某個(gè)元素內(nèi)的所有子元素(包括動(dòng)態(tài)加載的內(nèi)容)都已完成渲染,可以結(jié)合 requestAnimationFrame
創(chuàng)建一個(gè)循環(huán),定期檢查元素及其子元素的狀態(tài)。當(dāng)所有預(yù)期條件滿足時(shí),停止循環(huán)。
function checkRenderCompletion(element) {// 在這里定義您的檢查邏輯,比如檢查子元素?cái)?shù)量、計(jì)算布局、檢查特定CSS屬性等const isRendered = /* ... */;if (isRendered) {console.log('The targeted element and its content have finished rendering.');// 停止循環(huán)return;}requestAnimationFrame(() => checkRenderCompletion(element));
}const targetElement = document.querySelector('#your-element');
checkRenderCompletion(targetElement);
8.5. 5. 監(jiān)聽(tīng)特定資源加載事件
對(duì)于依賴特定資源(如圖片、字體、異步腳本等)完成渲染的元素,可以監(jiān)聽(tīng)這些資源的加載事件。例如,對(duì)于圖片,可以監(jiān)聽(tīng) img
元素的 load
事件。
const images = document.querySelectorAll('img');
images.forEach(img => {img.addEventListener('load', function () {console.log('An image has finished loading.');// 根據(jù)需要,檢查所有圖片是否已加載完成,以確定整個(gè)區(qū)域渲染完成});
});
8.6. 6. 使用自定義加載指示器/回調(diào)
對(duì)于自定義加載邏輯(如使用加載庫(kù)或組件),如果它們提供了加載完成的回調(diào)函數(shù)或狀態(tài)指示器,可以直接使用這些接口來(lái)判斷渲染完成。
const customLoader = new YourCustomLoader();
customLoader.onLoadComplete = function () {console.log('Custom loader has finished rendering its content.');
};
綜上所述,選擇合適的方法取決于具體的應(yīng)用場(chǎng)景和需求。您可以單獨(dú)使用或組合上述方法來(lái)準(zhǔn)確檢測(cè)當(dāng)前可視區(qū)域的渲染完成狀態(tài)。
9. 如何保障項(xiàng)目穩(wěn)定性
從前端視角來(lái)看,保障項(xiàng)目穩(wěn)定性主要關(guān)注以下幾個(gè)方面:
- 規(guī)范化的前端開(kāi)發(fā)流程:
-
- 遵循前端最佳實(shí)踐和編碼規(guī)范:如使用語(yǔ)義化的HTML,遵循CSS命名約定,編寫(xiě)可維護(hù)的JavaScript代碼,確保代碼風(fēng)格統(tǒng)一,易于閱讀和理解。
- 代碼審查:實(shí)施嚴(yán)格的代碼審查制度,確保代碼質(zhì)量,及時(shí)發(fā)現(xiàn)并修正潛在問(wèn)題,如DOM操作異常、內(nèi)存泄漏、性能瓶頸等。
- 版本控制與分支管理:使用Git進(jìn)行版本控制,遵循明確的分支策略(如主干開(kāi)發(fā)、特性分支、熱fix分支等),確保代碼合并過(guò)程中的穩(wěn)定性。
- 健壯的前端架構(gòu)設(shè)計(jì):
-
- 模塊化與組件化:采用模塊化和組件化開(kāi)發(fā)方式(如使用Webpack、Rollup進(jìn)行模塊打包,React、Vue等框架進(jìn)行組件化開(kāi)發(fā)),提高代碼復(fù)用性,降低模塊間耦合,便于維護(hù)和升級(jí)。
- 狀態(tài)管理:合理使用狀態(tài)管理庫(kù)(如Redux、Vuex、MobX等),確保應(yīng)用程序狀態(tài)的一致性和可預(yù)測(cè)性,減少因狀態(tài)管理不當(dāng)導(dǎo)致的UI渲染異常或數(shù)據(jù)混亂問(wèn)題。
- 路由管理:清晰的路由規(guī)劃和管理(如React Router、Vue Router),確保頁(yè)面跳轉(zhuǎn)邏輯正確,避免路由沖突或未定義路由引發(fā)的錯(cuò)誤。
- 全面的前端質(zhì)量保證:
-
- 自動(dòng)化測(cè)試:
-
-
- 單元測(cè)試:為關(guān)鍵邏輯、組件方法、鉤子函數(shù)等編寫(xiě)單元測(cè)試,使用Jest、Mocha等測(cè)試框架,確保代碼變更不影響既有功能。
- 端到端測(cè)試:使用Cypress、Puppeteer等工具進(jìn)行E2E測(cè)試,驗(yàn)證完整的用戶交互流程和跨組件通信,確保整個(gè)應(yīng)用的功能完整性和一致性。
- 性能測(cè)試:利用Lighthouse、WebPageTest等工具進(jìn)行性能基準(zhǔn)測(cè)試和優(yōu)化建議,關(guān)注加載速度、首屏渲染時(shí)間、可交互時(shí)間等關(guān)鍵指標(biāo)。
-
-
- 靜態(tài)代碼分析與 linting:使用ESLint、Stylelint等工具進(jìn)行代碼風(fēng)格檢查和潛在問(wèn)題檢測(cè),預(yù)防常見(jiàn)的語(yǔ)法錯(cuò)誤、未使用的變量、潛在的安全漏洞等。
- 瀏覽器兼容性測(cè)試:使用Browserslist、Autoprefixer等工具確保代碼兼容目標(biāo)瀏覽器范圍,利用BrowserStack、Sauce Labs等服務(wù)進(jìn)行多瀏覽器、多設(shè)備的實(shí)際測(cè)試。
- 優(yōu)化前端性能與用戶體驗(yàn):
-
- 資源優(yōu)化:壓縮、合并、懶加載、預(yù)加載等手段優(yōu)化CSS、JavaScript、圖片等資源,減少網(wǎng)絡(luò)請(qǐng)求次數(shù)和體積,提升加載速度。
- 響應(yīng)式設(shè)計(jì)與無(wú)障礙訪問(wèn):確保界面在不同屏幕尺寸和設(shè)備上適配良好,遵循WCAG標(biāo)準(zhǔn)提升無(wú)障礙性,提升用戶體驗(yàn)的同時(shí)降低因兼容性問(wèn)題引發(fā)的投訴或故障。
- 錯(cuò)誤捕獲與用戶反饋:使用try-catch、window.onerror、unhandledrejection等機(jī)制捕獲并上報(bào)前端異常,提供用戶反饋渠道,及時(shí)發(fā)現(xiàn)并修復(fù)問(wèn)題。
- 監(jiān)控與日志:
-
- 前端監(jiān)控:集成RUM(Real User Monitoring)工具(如Google Analytics、 Sentry、Datadog等),收集用戶端性能數(shù)據(jù)、異常信息、用戶行為數(shù)據(jù)等,用于分析性能瓶頸、定位問(wèn)題源頭。
- 前端日志:通過(guò)console.log、console.error、專門的日志庫(kù)等方式記錄關(guān)鍵操作、異常情況等信息,便于問(wèn)題排查。
- 持續(xù)集成與部署:
-
- CI/CD流程:配置自動(dòng)化構(gòu)建、測(cè)試、部署流水線(如GitHub Actions、Jenkins、Travis CI等),確保每次代碼變更經(jīng)過(guò)充分驗(yàn)證后再發(fā)布到生產(chǎn)環(huán)境。
- 版本控制與包管理:使用npm、yarn等包管理工具,遵循語(yǔ)義化版本控制,鎖定依賴版本,防止第三方庫(kù)更新引發(fā)的兼容性問(wèn)題。
通過(guò)以上措施,從前端視角出發(fā),可以系統(tǒng)性地保障項(xiàng)目的穩(wěn)定性,確保用戶在使用過(guò)程中獲得流暢、一致且無(wú)明顯故障的體驗(yàn)。同時(shí),也為后續(xù)的維護(hù)、升級(jí)和擴(kuò)展打下堅(jiān)實(shí)基礎(chǔ)。