性能-网站和应用的支柱

  • 流量
  • 搜索
  • 转换率
  • 用户体验

现状

移动端

  • 设备硬件,网速,屏幕尺寸,交互方式
  • 用户更缺少耐心,>3s 加载导致 53% 的跳出率(bounce rate)
  • 持续增长的移动用户和移动电商业务

性能指标和优化目标

性能优化-加载

  • 瀑布图
  • HAR 存储
  • 速度指数(speed index)
  • 重要测量指标

    • speed index
    • TTFB (Time To First Byte)
    • 页面加载时间
    • 首次渲染

      性能优化-响应

  • 交互动作的反馈时间

  • FPS (Frames Per Second)
  • 异步请求的完成时间

    RAIL 测量模型

  • Response 响应

    • 100ms 内响应用户事件

input-handling-time.png

  • Animation 动画
    • 动画每 16.7ms 传输新的一帧在屏幕上
  • Idle 空闲
    • 每一个空闲任务不超过 50ms
    • 尽可能增加空闲时间
  • Load 加载
    • 3G 中等设备 5s 内完成内容加载并可交互

性能测量工具

Chrome DevTools 开发调试、性能评测

  • Network 网络加载分析
  • Performance 性能分析
  • Throttling 调整网络吞吐
  • Audit(Lighthouse)

    Lighthouse 网站整体质量评估

    WebPageTest 多测试地点、全面性能报告

  • waterfall chart 请求瀑布图

  • first view 首页访问
  • repeat view 二次访问

    本地部署 webpagetest

  • 安装 docker

  • 拉取镜像 ```bash docker pull webpagetest/server

docker pull webpagetest/agent

  1. - 运行实例
  2. ```bash
  3. docker run -d -p 4000:80 webpagetest/server
  4. docker run -d -p 4001:80 --network="host" -e "SERVER_URL=http://localhost:4000/work/" -e "LOCATION=Test" webpagetest/agent
  • 配置 server

    mkdir wpt-mac-server
    cd wpt-mac-server
    vim Dockerfile
    
    FROM webpagetest/server
    ADD locations.ini /var/www/html/settings/
    
    vim location.ini
    
    [locations]
    1=Test_loc
    [Test_loc]
    1=Test
    label=Test Location
    group=Desktop
    [Test]
    browser=Chrome,Firefox
    label="Test Location"
    connectivity=LAN
    
  • 打包 server

    docker build -t wpt-mac-server .
    
  • 配置 agent

    cd ../
    mkdir wpt-mac-agent
    cd wpt-mac-agent
    vim Dockerfile
    
    FROM webpagetest/agent
    ADD script.sh /
    ENTRYPOINT /script.sh
    
    vim script.sh
    
    #!/bin/bash
    set -e
    if [ -z "$SERVER_URL" ]; then
    echo >&2 'SERVER_URL not set'
    exit 1
    fi
    if [ -z "$LOCATION" ]; then
    echo >&2 'LOCATION not set'
    exit 1
    fi
    EXTRA_ARGS=""
    if [ -n "$NAME" ]; then
    EXTRA_ARGS="$EXTRA_ARGS --name $NAME"
    fi
    python /wptagent/wptagent.py --server $SERVER_URL --location $LOCATION $EXTRA_ARGS --xvfb --dockerized -vvvvv --shaper none
    
    chmod u+x script.sh
    
  • 打包 agent

    docker build -t wpt-mac-agent .
    
  • 用新镜像运行实例 (注意先停掉之前运行的containers) ```bash docker ps

docker stop serverID agentID

docker run -d -p 4000:80 wpt-mac-server

docker run -d -p 4001:80 —network=”host” -e “SERVER_URL=http://localhost:4000/work/“ -e “LOCATION=Test” wpt-mac-agent


<a name="clGvf"></a>
## 常用的性能测量 APIs
<a name="yHOJS"></a>
### 关键性能指标计算

DNS 解析耗时: domainLookupEnd - domainLookupStart TCP 连接耗时: connectEnd - connectStart SSL 安全连接耗时: connectEnd - secureConnectionStart 网络请求耗时 (TTFB): responseStart - requestStart 数据传输耗时: responseEnd - responseStart DOM 解析耗时: domInteractive - responseEnd 资源加载耗时: loadEventStart - domContentLoadedEventEnd First Byte时间: responseStart - domainLookupStart 白屏时间: responseEnd - fetchStart 首次可交互时间: domInteractive - fetchStart DOM Ready 时间: domContentLoadEventEnd - fetchStart 页面完全加载时间: loadEventStart - fetchStart http 头部大小: transferSize - encodedBodySize 重定向次数:performance.navigation.redirectCount 重定向耗时: redirectEnd - redirectStart

```javascript
// 计算一些关键的性能指标
window.addEventListener('load', (event) => {
    // Time to Interactive
    let timing = performance.getEntriesByType('navigation')[0];
    console.log(timing.domInteractive);
    console.log(timing.fetchStart);
    let diff = timing.domInteractive - timing.fetchStart;
    console.log("TTI: " + diff);
})

PerformanceObserver

// 观察长任务
const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
        console.log(entry)
    }
})

observer.observe({entryTypes: ['longtask']})

visibilitychange

// 页面可见性的状态监听
let vEvent = 'visibilitychange';
if (document.webkitHidden != undefined) {
    // webkit prefix detected
    vEvent = 'webkitvisibilitychange';
}

function visibilityChanged() {
    if (document.hidden || document.webkitHidden) {
        console.log("Web page is hidden.")
    } else {
        console.log("Web page is visible.")
    }
}

document.addEventListener(vEvent, visibilityChanged, false);

navigator.connection

var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
var type = connection.effectiveType;

function updateConnectionStatus() {
  console.log("Connection type changed from " + type + " to " + connection.effectiveType);
  type = connection.effectiveType;
}

connection.addEventListener('change', updateConnectionStatus);

参考