设计网站都有什么作用是什么做网站优化需要多少钱
张小明 2026/1/8 12:06:07
设计网站都有什么作用是什么,做网站优化需要多少钱,北京seo优化公司,手机网站最简单三个步骤如果你正在寻找一种现代、可靠的方式来测量网站性能#xff0c;Playwright 可能正是你需要的工具。虽然它主要以自动化测试闻名#xff0c;但其强大的性能监控能力却常常被忽视。在这篇文章中#xff0c;我将分享如何利用 Playwright 来测量那些影响用户体验的关键性能指标。…如果你正在寻找一种现代、可靠的方式来测量网站性能Playwright 可能正是你需要的工具。虽然它主要以自动化测试闻名但其强大的性能监控能力却常常被忽视。在这篇文章中我将分享如何利用 Playwright 来测量那些影响用户体验的关键性能指标。为什么选择 Playwright 进行性能测试你可能会问“已经有 Lighthouse 和 WebPageTest 这样的专用工具为什么还要用 Playwright” 原因很简单灵活性和集成度。Playwright 允许你将性能测试无缝集成到现有的自动化测试流程中可以在多种浏览器环境下运行并且能够模拟真实的用户交互场景。我最初是在为一个需要登录后才能测试的页面寻找性能监控方案时发现了 Playwright 的这个能力。其他工具难以处理身份验证而 Playwright 轻松解决了这个问题。环境搭建与基础配置首先确保你已经安装了 Node.js建议版本 14 或更高。创建一个新目录并初始化项目mkdirplaywright-performancecdplaywright-performancenpminit -ynpminstallplaywright接下来创建一个基本脚本文件performance-test.jsconst{chromium}require(playwright);(async(){// 启动浏览器建议使用无头模式以提高性能constbrowserawaitchromium.launch({headless:true});constcontextawaitbrowser.newContext();constpageawaitcontext.newPage();// 在这里添加性能测量代码awaitbrowser.close();})();测量核心 Web 性能指标1. 页面加载时间最基本的指标是页面完全加载所需的时间// 开始计时conststartTimeDate.now();// 导航到目标页面awaitpage.goto(https://example.com,{waitUntil:load// 等待页面完全加载});// 计算加载时间constloadTimeDate.now()-startTime;console.log(页面加载时间:${loadTime}ms);但waitUntil: load可能不够准确因为它不一定会等待所有异步内容完成。我通常使用networkidle选项它会等待网络活动基本停止awaitpage.goto(https://example.com,{waitUntil:networkidle// 等待网络空闲});2. 核心 Web 指标Core Web VitalsGoogle 提出的核心 Web 指标对用户体验至关重要。通过 Playwright 我们可以测量其中的几项最大内容绘制LCP// 测量LCP最大内容绘制constlcpawaitpage.evaluate((){returnnewPromise((resolve){// 创建LCP性能观察者constobservernewPerformanceObserver((entryList){constentriesentryList.getEntries();// 取最后一个LCP条目最新的LCP值constlastEntryentries[entries.length-1];// 优先使用renderTime无则回退到loadTimeresolve(lastEntry.renderTime||lastEntry.loadTime);});// 监听LCP事件buffered: true 捕获历史事件observer.observe({type:largest-contentful-paint,buffered:true});// 提前检查如果LCP已触发直接返回最新值避免等待constexistingLcpEntriesperformance.getEntriesByType(largest-contentful-paint);if(existingLcpEntries.length0){constlastEntryexistingLcpEntries[existingLcpEntries.length-1];resolve(lastEntry.renderTime||lastEntry.loadTime);observer.disconnect();// 停止监听释放资源}});});// 输出LCP结果保留1位小数提升可读性console.log(LCP:${lcp?lcp.toFixed(1):未检测到}ms);// 性能标准✅ 良好(2500ms) | ⚠️ 需优化(2500-4000ms) | ❌ 差(4000ms)累积布局偏移CLS// 测量CLS累积布局偏移constclsawaitpage.evaluate((){letclsValue0;constobservernewPerformanceObserver((entryList){for(constentryofentryList.getEntries()){// 排除用户输入后产生的布局偏移避免误判if(!entry.hadRecentInput){clsValueentry.value;}}});// 监听布局偏移事件buffered: true 捕获历史事件observer.observe({type:layout-shift,buffered:true});// 等待5秒以捕获可能的延迟布局变化返回最终CLS值returnnewPromise((resolve){setTimeout((){resolve(clsValue);},5000);});});// 输出CLS结果并标注参考标准console.log(CLS:${cls});// 良好标准小于0.1 | 需要优化0.1~0.25 | 差大于0.253. 资源加载分析了解各个资源的加载性能有助于定位问题// 获取所有资源的加载时间constresourcesawaitpage.evaluate((){constresourcesperformance.getEntriesByType(resource);returnresources.map(resource({name:resource.name,duration:resource.duration,type:resource.initiatorType}));});// 找出加载最慢的资源constslowestResourcesresources.sort((a,b)b.duration-a.duration).slice(0,5);console.log(加载最慢的5个资源:,slowestResources);4. 交互响应时间对于单页应用SPA交互响应时间尤为重要// 测量按钮点击响应时间constbuttonawaitpage.$(#submit-button);constclickStartTimeDate.now();awaitbutton.click();// 等待某个表示交互完成的变化awaitpage.waitForSelector(.success-message,{timeout:5000});constclickResponseTimeDate.now()-clickStartTime;console.log(交互响应时间:${clickResponseTime}ms);实战完整的性能测试脚本下面是一个整合了多个指标的完整示例const{chromium}require(playwright);asyncfunctionrunPerformanceTest(url){constbrowserawaitchromium.launch({headless:true});constcontextawaitbrowser.newContext();constpageawaitcontext.newPage();console.log(正在测试:${url});// 监听性能指标awaitpage.evaluateOnNewDocument((){// 这里可以注入性能监控代码window.performanceMetrics{lcp:null,cls:null,fid:null};});// 导航到页面conststartTimeDate.now();awaitpage.goto(url,{waitUntil:networkidle});constnavigationTimeDate.now()-startTime;// 等待可能的内容加载awaitpage.waitForTimeout(2000);// 收集性能指标constperformanceDataawaitpage.evaluate((){// 获取导航计时constnavigationperformance.getEntriesByType(navigation)[0];// 获取绘制指标constpaintEntriesperformance.getEntriesByType(paint);constfcppaintEntries.find(entryentry.namefirst-contentful-paint);// 获取LCPconstlcpEntriesperformance.getEntriesByType(largest-contentful-paint);constlcplcpEntries.length0?lcpEntries[lcpEntries.length-1]:null;return{dnsTime:navigation.domainLookupEnd-navigation.domainLookupStart,tcpTime:navigation.connectEnd-navigation.connectStart,ttfb:navigation.responseStart-navigation.requestStart,domContentLoaded:navigation.domContentLoadedEventEnd,loadEvent:navigation.loadEventEnd,fcp:fcp?fcp.startTime:null,lcp:lcp?lcp.startTime:null};});// 输出性能测试结果console.log(\n 性能测试结果 );console.log(总导航时间:${navigationTime}ms);console.log(DNS查询:${performanceData.dnsTime}ms);console.log(TCP连接:${performanceData.tcpTime}ms);console.log(首字节时间(TTFB):${performanceData.ttfb}ms);console.log(首次内容绘制(FCP):${performanceData.fcp}ms);console.log(最大内容绘制(LCP):${performanceData.lcp}ms);console.log(DOM内容加载:${performanceData.domContentLoaded}ms);console.log(页面完全加载:${performanceData.loadEvent}ms);// 检查是否达到性能阈值constthresholds{lcp:2500,ttfb:800,fcp:1800};console.log(\n 性能评估 );if(performanceData.lcpthresholds.lcp){console.warn(⚠️ LCP${performanceData.lcp}ms 超过阈值${thresholds.lcp}ms);}else{console.log(✅ LCP 符合标准);}awaitbrowser.close();returnperformanceData;}// 运行测试runPerformanceTest(https://example.com).catch(console.error);进阶技巧与最佳实践1. 模拟不同网络条件const{chromium}require(playwright);asyncfunctiontestWithNetworkConditions(url){constbrowserawaitchromium.launch();constcontextawaitbrowser.newContext();// 模拟3G网络constslow3G{offline:false,downloadThroughput:500*1024/8,// 500 KbpsuploadThroughput:500*1024/8,latency:400};constpageawaitcontext.newPage();// 设置网络节流constclientawaitcontext.newCDPSession(page);awaitclient.send(Network.emulateNetworkConditions,slow3G);console.log(正在3G网络条件下测试...);awaitpage.goto(url);awaitbrowser.close();}2. 多次测试取平均值性能测试结果可能会有波动多次测试取平均值更加可靠asyncfunctionrunAverageTest(url,iterations5){constresults[];for(leti0;iiterations;i){console.log(第${i1}/${iterations}次测试...);constresultawaitrunPerformanceTest(url);results.push(result);// 每次测试之间等待一会if(iiterations-1){awaitnewPromise(resolvesetTimeout(resolve,2000));}}// 计算平均值constaverages{};constmetricsObject.keys(results[0]);metrics.forEach(metric{constsumresults.reduce((acc,result)acc(result[metric]||0),0);averages[metric]sum/results.length;});console.log(\n 平均性能结果 );Object.entries(averages).forEach(([metric,value]){console.log(${metric}:${Math.round(value)}ms);});returnaverages;}3. 生成可视化报告你可以将结果输出为JSON然后使用其他工具如Chart.js生成可视化报告constfsrequire(fs);asyncfunctiongenerateReport(url){constdataawaitrunPerformanceTest(url);constreport{timestamp:newDate().toISOString(),url:url,metrics:data,thresholds:{good:{lcp:2500,fcp:1800,cls:0.1},needsImprovement:{lcp:4000,fcp:3000,cls:0.25}}};fs.writeFileSync(performance - report - $ { Date.now() }.json,JSON.stringify(report,null,2));console.log(报告已生成);}常见问题与解决方案问题1性能指标获取不到如果某些性能指标返回null可能是因为页面加载太快性能条目已经被清除。可以尝试在页面加载前就注入性能观察器awaitpage.evaluateOnNewDocument((){// 在页面任何代码执行前开始监控constobservernewPerformanceObserver((list){window.lcpEntrylist.getEntries().slice(-1)[0];});observer.observe({type:largest-contentful-paint,buffered:true});});问题2测试结果不稳定网络波动、缓存等因素可能导致测试结果不一致。解决方案每次测试前清除缓存多次测试取平均值在相对稳定的网络环境下运行测试constcontextawaitbrowser.newContext({bypassCSP:true,// 禁用缓存viewport:null});问题3需要测试登录后的页面Playwright 的优势在这里体现asyncfunctiontestAuthenticatedPage(){constbrowserawaitchromium.launch();constcontextawaitbrowser.newContext();constpageawaitcontext.newPage();// 先登录awaitpage.goto(https://example.com/login);awaitpage.fill(#username,your-username);awaitpage.fill(#password,your-password);awaitpage.click(#login-button);awaitpage.waitForNavigation();// 现在测试需要认证的页面console.log(测试已登录状态下的性能...);awaitrunPerformanceTest(https://example.com/dashboard);awaitbrowser.close();}推荐阅读黑盒测试方法—等价类划分法大学毕业后转行软件测试我后悔了软件测试 | 测试开发 | Android动态权限详解软件测试的测试方法及测试流程软件测试 | 测试开发 | Android App 保活服务的配置与禁用