Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

聚焦 Web 性能指标 TTI #88

Open
pfan123 opened this issue Apr 1, 2021 · 0 comments
Open

聚焦 Web 性能指标 TTI #88

pfan123 opened this issue Apr 1, 2021 · 0 comments

Comments

@pfan123
Copy link
Owner

pfan123 commented Apr 1, 2021

常见web 性能指标

  • 首次绘制时间 (FP) - 即 First Paint,为首次渲染的时间点
  • 首次内容绘制时间(FCP):即First Contentful Paint,为首次有内容渲染的时间点
  • 首次有效绘制时间(FMP) - 即First Meaning Paint,用户启动页面加载与页面呈现首屏之间的时间
  • Dom ready - domContentLoadEventEnd - fetchStart
  • 页面完全加载耗时 - 页面完全加载的时间(load事件发生的时间)
  • 完全可交互时间 (TTI) - 即Time to interactive,记录从页面加载开始,到页面处于完全可交互状态所花费的时间

如果你经常做网站优化,可能会陷入一个性能指标的泥潭即「面向指标优化」。真正的用户体验从来不是指标决定,相反它应该最真实的反映用户行为。

所以本节我们就来研究 TTI(Time to Interactive),话题展开之前,我们先来了解一些背景知识。

推荐 https://web.dev/,google 面向开发者推荐的,给 Web应用指导和分析。

一、RAIL 模型

RAIL 是一种以用户为中心的性能模型。每个网络应用均具有与其生命周期有关的四个不同方面,且这些方面以不同的方式影响着性能:
RAIL 性能模型

1.响应:输入延迟时间(从点按到绘制)小于 100 毫秒。
用户点按按钮(例如打开导航)。

2.动画:每个帧的工作(从 JS 到绘制)完成时间小于 16 毫秒。
用户滚动页面,拖动手指(例如,打开菜单)或看到动画。 拖动时,应用的响应与手指位置有关(例如,拉动刷新、滑动轮播)。 此指标仅适用于拖动的持续阶段,不适用于开始阶段。

3.空闲:主线程 JS 工作分成不大于 50 毫秒的块。
用户没有与页面交互,但主线程应足够用于处理下一个用户输入。

4.加载:页面可以在 1000 毫秒内就绪。
用户加载页面并看到关键路径内容。

如果要提升网站用户体验,[RAIL](Measure performance with the RAIL model) 是个不错的评估模型。

二、解读 TTI(页面可交互时间)

TTI(页面可交互时间)度量标准衡量页面在用户可以与之交互之前所花费的时间,即页面对点击做出响应之前的时间。这取决于何时:

  • 页面显示有用的内容(由第一个有内容的绘图确定)

  • 页面上最可见的内容是交互式的(可单击或响应鼠标悬停时,等等)

  • 页面在最长 50 毫秒内响应用户交互

tti

在实践中,用于计算TTI的算法同时观察瀑布和网络活动。确定互动时间的三个阶段是:

  • 选择一个相关的起点,例如第一个 Contentful Paintdomcontentloadended

  • 从这一点出发,寻找一个网络稳定 5 秒的窗口(不包含长任务);

  • 一旦发现了这一点,回顾最后一个长任务的结束,并将该时间报告为“交互时间”。

这意味着在文档分析完成之前不可能估计 TTI。要了解 TTI,我们需要知道它的计算规则,先来看下面这张图:
TTI

官方文档中找到了如下描述:
First Idle is the first early sign of time where the main thread has come at rest and the browser has completed a First Meaningful Paint.

Time to Interactive is after First Meaningful Paint. The browser’s main thread has been at rest for at least 5 seconds and there are no long tasks that will prevent immediate response to user input.

我们可以简单的理解一下:
1.First Idle 是主线程处于静止状态且浏览器已完成 First Meanfulful Paint 的第一个早期迹象;
2.TTIFMP 之后,浏览器主线程静止至少 5s,并且没有可以阻断用户交互响应的「长任务」。

如果你对 FMP 还不了解,不妨先看看这篇文章:网站性能指标 - FMP。除此之外,第二条中提到的「长任务」又是什么呢?

三、Long Task(长任务)

对于「长任务」,我们通过如下图示说明:
长任务

对于用户而言,任务耗时较长表现为滞后或卡顿,而这也是目前网页不良体验的主要根源。

如何测量 Long Task

// Jartto's Demo
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // TODO...
    console.log(entry);
  }
});

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

控制台输出结果如下:

{
  "name": "self",
  "entryType": "longtask",
  "startTime": 315009.59500001045,
  "duration": 99.9899999878835,
  "attribution": [
    {
      "name": "unknown",
      "entryType": "taskattribution",
      "startTime": 0,
      "duration": 0,
      "containerType": "window",
      "containerSrc": "",
      "containerId": "",
      "containerName": ""
    }
  ]
}

Long Tasks API 可以将任何耗时超过 50 毫秒的任务标示为可能存在问题,并向应用开发者显示这些任务。 选择 50 毫秒的时间是为了让应用满足在 100 毫秒内响应用户输入的 RAIL 指导原则。

实际开发过程中,我们可以通过一个 hack 来检查页面中「长任务」的代码:

// detect long tasks hack
(function detectLongFrame() {
    let lastFrameTime = Date.now();
    requestAnimationFrame(function() {
        let currentFrameTime = Date.now();
        if (currentFrameTime - lastFrameTime > 50) {
        // Report long frame here...
        }
        detectLongFrame(currentFrameTime);
    });
}());

四、如何计算 TTI?

在计算之前,我们先来看一下 Timing API
Timing API

Google` 官方文档中有一段描述:
`Note: Lower Bounding FirstInteractive at DOMContentLoadedEnd DOMContentLoadedEnd is the point where all the DOMContentLoaded listeners finish executing. It is very rare for critical event listeners of a webpage to be installed before this point. Some of the firstInteractive definitions we experimented with fired too early for a small number of sites, because the definitions only looked at long tasks and network activity (and not at, say, how many event listeners are installed), and sometimes when there are no long tasks in the first 5-10 seconds of loading we fire FirstInteractive at FMP, when the sites are often not ready yet to handle user inputs. We found that if we take max(DOMContentLoadedEnd, firstInteractive) as the final firstInteractive value, the values returned to reasonable region. Waiting for DOMContentLoadedEnd to declare FirstInteractive is sensible, so all the definitions introduced below lower bound firstInteractive at DOMContentLoadedEnd.

所以,我们可以通过 domContentLoadedEventEnd 来粗略的进行估算:

// 页面可交互时间 
TTI: domContentLoadedEventEnd - navigationStart,

domContentLoadedEventEnd:文档的 DOMContentLoaded 事件的结束时间。

The domContentLoadedEventEnd attribute MUST return a DOMHighResTimeStamp with a time value equal to the time immediately after the current document's DOMContentLoaded event completes.

如果你觉得上述计算过于复杂,可以通过 Google 实验室提供的 Polyfill 来获取。

五、TTI 指标监控

我们可以通过 Google TTI Polyfill来对 TTI 进行监测。

1.安装

npm install tti-polyfill

2.使用

import ttiPolyfill from './path/to/tti-polyfill.js';
ttiPolyfill.getFirstConsistentlyInteractive(opts).then((tti) => {
  // Use `tti` value in some way.
});

Other Resources

Measure performance with the RAIL model

First Interactive and Consistently Interactive

User-centric performance metrics

Focusing on the Human-Centric Metrics

Navigation Timing Level 2

以用户为中心的性能指标【译】

Understand and improve the Time To Interactive

让你的网页更丝滑(一)

火山引擎-页面加载

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant