应用场景说明
埋点逻辑说明
埋点逻辑分为两种:
无侵入式埋点:业务方无需关注埋点逻辑,将自己的页面(组件)传入封装好的HOC中即可。
自定义埋点:业务方自己决定埋点的时机,调用
pageStart
、pageUpdate
、pageEnd
等API。
无侵入式埋点说明
@emas/emas-appmonitor-perf提供了两个无侵入式API:
statelessHOC:适用于无状态的页面。
statefulHOC:适用于有状态的页面。
statelessHOC
statelessHOC主要适用于无状态的页面(组件),无状态组件一般是指组件内部不包含状态或者组件内部状态的变更并不影响组件主要UI的渲染逻辑:
statelessHOC会自动计算页面的渲染时间并在页面离开时上报埋点,渲染时间计算公式为:
constructor - componentDidMount
举例说明:
登录页面:常见的登录页面进入页面后就会完成整个页面主要UI的渲染,这种情况下可以认为登录页面已经完成渲染,其页面性能已经可以统计出来,登录页面内部的其他状态变化也并不会影响主UI的渲染,例如,常见的登录页面内部的状态变化主要是请求登录接口时会显示loading,登录接口请求失败后状态改变,loading消失,显示错误信息,这种状态的改变一般并不会计算到整体页面的性能数据中。
Splash页面:常见的splash页面展示的都是静态的View。
设置页面:常见的设置页面也是在进入页面后就完成了主要UI的渲染。
页面参数由前一个页面传入:这类页面的渲染参数由前一个页面(组件)完全传递进来,进入页面后也完成了主要UI的渲染。
传入statelessHOC的组件可以是类组件,也可以是函数式组件。
statefulHOC
statefuleHOC主要适用于有状态的业务页面(组件),有状态页面(组件)指的是页面(组件)完整的UI显示是基于状态的变化决定的。
statefuleHOC会自动计算页面的渲染时间并在页面离开时上报埋点,计算公式为:
componentDidMount - componentDidUpdate(第一次Update)
举例说明:
列表页:常见列表页面的业务逻辑是进入页面后先显示loading视图,再请求网络接口获取list数据,接口请求完成后将获取到的list更新到页面,这种情况下页面的渲染时间应该计算的是list视图完成渲染的时间。
statefulHOC只会记录组件第一次update的时间戳,后续的update都不会再记录,如果页面(组件)的主视图是在多次update以后才完成渲染,这类页面(组件)不建议使用statefulHOC,建议使用pageStart等API自定义埋点。
传入statefuleHOC的组件必须是类组件,不支持函数式组件。
自定义埋点说明
自定义埋点的适用场景为:
有状态的函数式组件:比如列表页面如果使用函数式组件的方式(结合Hooks)搭建,则无法传入statefuleHOC,这种情况下就需要业务方自己调用pageStart、pageEnd等API主动上报埋点。
有复杂场景的页面:建议使用自定义埋点的方式上报统计数据。
举例说明:
某个页面由多个接口组成,每个接口负责某一视图区域的渲染,这种情况下对于页面渲染时间如何计算需要业务方自行决定,由于statefulHOC只记录第一次update的时间戳,如果将这类复杂页面传入statefulHOC则有可能导致整体的渲染时间不准,所以这类页面不建议使用statefuleHOC。
自定义埋点API调用方式:
调用链:pageStart->pageUpdate(可选)->pageEnd
调用pageStart
和pageUpdate
后只是会记录相应数据,只有在调用pageEnd
后才上传当前的埋点数据。
类组件:建议将pageEnd放在componentWillUnmount中,即在页面离开时再上报,与页面本身的业务逻辑分开。
示例代码:
class TestComponent extends React.Component { constructor(props) { super(props); } componentDidMount() { pageStart('TestComponent'); } componentDidUpdate(prevProps, prevState) { pageUpdate('TestComponent'); } componentWillUnmount() { pageEnd('TestComponent'); } render() { ... } }
函数式组件:由业务方自定义pageEnd的调用时机。
示例代码:
const CustomSpm = () => { const [data, setData] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { pageStart('CustomSpm'); const fetchData = () => { fetch('https://xxxx') .then(response => response.json()) .then(responseJson => { setData(responseJson.xxx); }) .catch(error => console.error(error)) .finally(() => { setLoading(false); pageEnd('CustomSpm'); }); }; fetchData(); }, []); return ( ... ); }; export default CustomSpm;