html页面加载时判断系统时间,一种新的页面加载时间检测方式

在一次组内会议中,被分配到了这样一个技术研究需求,目的是通过检测页面加载耗时,来对页面进行针对性的优化.拿到这个任务之后,立马去搜集了一些网上现有的资料,并作出了一些总结.

目前实现检测的几种方式

基本思路

通常是利用 swizlling

在 viewDidLoad

方法里保存一个初始时间,然后在 viewDidAppear

里得到页面出现的时间.

@implementation UIViewController (LoadTime)

+ (void)load

{

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

swizzleMethod([UIViewController class], @selector(viewDidLoad), @selector(my_viewDidLoad));

});

swizzleMethod([UIViewController class], @selector(viewDidAppear), @selector(my_viewDidAppear:));

});

}

- (void)my_viewDidLoad

{

NSDate *date = [NSDate date];

// 保存开始时间

_date = date;

[self my_viewDidLoad];

}

- (void)my_viewDidAppear:(BOOL)animated{

[self my_viewDidAppear:animated];

// 得到加载时间

NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:_date];

NSLog(@"Page %@ cost %g to be appeared", [self class], duration);

}

@end

复制代码

一种基于KVO的页面加载时间获取(作者五子棋)

这篇博客指出了上述方法的问题,你hook的其实是父类 UIViewController

的方法,子类其实是调用了 [super xxxxxx]

方法,这种处理方式没办法对每种页面都进行处理,需要各自建立对应分类.

于是作者突发奇想,利用KVO拿到派生的子类进行 IMP

的替换,从而解决了这个问题. 以上两种方式只能得出代码加载时间,如果某些页面和网络有关,网络请求这部分时间就很难拿到了.

「无侵入页面加载完成检测」的一些思路(作者Limboy)

这个方法是我完全没有想到的一种处理方式.利用 图像纯色占比

来判断当前页面是否是加载完成.简单来说,就是开启一个 CADisplayLink

定时器,对当前页面进行截图,然后利用计算纯色占比的算法算出比例,当比例大于某一个阈值,就说明页面已经加载成功了.这种方法我觉得是最直观的方法,但作者也列举了一些问题:

1.需要主动去截屏检测,而不能加载完成后告知。这其中的差别在于无法得知具体哪个时间加载完成了。

2.有些页面被故意设计成有较多留白,这时就不容易判断了。

3.「未加载完成」不同的页面会有不同的表现。

4.当用户滑动时,有可能之前的页面已经加载了

美团Hertz的思路

这篇文章介绍了美团关于性能监控的一些措施,也提到了 iOS 中页面加载时间检测的方式: 在iOS中我们采取了不同的做法,Hertz在配置文件中指定最终渲染页面的某个元素的tag,并在网络请求成功后开启CADisplayLink检查该元素是否出现在根节点下面。

总结下来的三个问题

问题1

:即使解决了无法直接hook子类的实现,但是也不能得到确切的加载时间如下面的例子:

- (void)viewDidLoad {

[super viewDidLoad];

self.view.backgroundColor = [UIColor whiteColor];

// 模拟了一个异步网络请求

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

sleep(3);

dispatch_async(dispatch_get_main_queue(), ^{

TempView *tView = [[TempView alloc] init];

tView.frame = CGRectMake(10, 20, 300, 200);

tView.backgroundColor = [UIColor orangeColor];

[self.view addSubview:tView];

});

});

}

复制代码

在这个例子中,用户所感受到的加载完成应该是 tView

在网络请求之后显示的时间.单纯的hook生命周期方法是无法获取网络延迟这段时间的.

问题2

:如果开启定时器进行页面检测截图,消耗内存的同时也会影响页面渲染,可能会造成性能问题.

问题3

:美团这种思路是可行的,但是这个 tag

该怎么打呢,如果是一个 纯tableView

的控制器显示该怎么判定呢, webview

呢?.

新的思路

这里我借鉴了美团的思路,但又有所不同.

我们先弄清楚2个问题:

1.我们检测页面加载时长的目的主要是为了检测 某些页面

从加载到显示的时间,通常页面的出现除了页面自身的渲染出现,还伴随着接口数据的刷新,有些界面依赖网络请求,有些界面依赖本地读取或者直接显示静态页面.

2.并不是所有的界面都需要进行检测,我们应该把监测重点放到一些用户常用的界面上,当然,能覆盖越多越能发现更多可能的问题.

所以我们只需要检测某个控制器中的某个 关键子view

出现,就可以确定这个时间.那我们怎么判断这些子页面真的显示呢?

visibleCells

知道如何判断页面显示了,那么我们需要一个配置文件,来指定那些页面 关键子view

的类型和其它属性.为了能够灵活配置,建议通过后台接口下发一个json,当然也可以本地配置一个dictionary.

我这里的文件格式如下:

/*

TargetSubview:关键子view

TargetSubviewType:子view的类型 0:UITableView/UICollectionView 1:NormalView 2:Webview

TargetEmptyViewType:可能会有的空白view类型

*/

@"ViewController":@{

@"TargetSubview" : @"UITableView",

@"TargetSubviewType" : @(0),

@"TargetEmptyViewType":@"NoDataView"

},

@"TempViewController":@{

@"TargetSubview" : @"TempView",

@"TargetSubviewType" : @(1),

@"TargetEmptyViewType":@"NoDataView"

},

@"TempWebviewController":@{

@"TargetSubview" : @"WKWebView",

@"TargetSubviewType" : @(2),

@"TargetEmptyViewType":@"NoDataView"

}

复制代码

然后我们就可以 hook UIViewController

的 viewDidLoad

方法,拿到初始时间,同时开启一个 CADisplayLink

定时器进行检测.

在定时器的方法里,我们就开始根据需要检测的页面,找到目标的子view,然后根据view类型进行相应的判断即可.如果符合判断条件,就可以进行上报了.

注意点:

1.对于空白页的处理,需要考虑多种情况,例如是直接加在关键子view里还是加在控制器中.

2.启动的广告页是否对首页加载有影响.

3.这里遍历子控件的时候,注意子控件层次不能太深,最好是一层,不然可能超过16.7ms,造成误报,这种情况是一个比较蛋疼的点,需要我们去控制子view的层级,但是为了更精准的获得加载时间,

这一步也很值得,这也是说为啥要用后台接口去控制,就是为了在业务发生变化之后能灵活调整view的层级.

以上就是我的检测思路,并且项目中已经运行了几个版本,中间也发现了不少问题,并得以解决.

这里有一个 比较简单的demo

,可以让大家了解一下,有啥问题,欢迎指正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 你可以使用 JavaScript 来获取页面加载完毕后的内容。下面是一种方法: 1. 在 HTML 页面中,添加一个 JavaScript 函数,该函数将在页面加载完毕后运行: ``` <body onload="myFunction()"> ``` 2. 在 JavaScript 中,使用 `document.getElementById` 或其他 JavaScript 方法获取你想要的元素: ``` function myFunction() { var element = document.getElementById("myElement"); // Do something with the element } ``` 3. 如果你想获取整个页面的内容,可以使用 `document.body.innerHTML` 方法: ``` function myFunction() { var content = document.body.innerHTML; // Do something with the content } ``` 请注意,如果页面包含大量内容,获取整个页面的内容可能会导致性能问题。 ### 回答2: 在PHP中,无法直接获取页面加载完毕后的内容,因为PHP是在服务器端执行的语言,所以它在页面加载完毕后就已经完成了任务并将结果返回给客户端。但是,我们可以通过其他方式获取页面加载完毕后的内容。 一种方法是使用JavaScript中的Ajax技术来异步请求服务器端获取最的内容。在页面加载完成后,可以使用JavaScript的事件监听器来触发Ajax请求,从而获取更后的页面内容。通过这种方式,我们可以在页面中动态显示最的内容。 另一种方法是使用JavaScript的Document对象的readyState属性来检测页面加载状态。当readyState属性的值为"complete",表示页面已经加载完毕。在PHP中,可以通过JavaScript内嵌在HTML代码中的方式,使用document.readyState属性来判断页面是否加载完毕,当页面加载完毕后,我们可以执行一些后续的操作,比如获取页面中的元素内容等。 总之,PHP本身无法直接获取页面加载完毕后的内容,但可以通过JavaScript等前端技术实现在加载完毕后获取最的内容。 ### 回答3: 在PHP中,无法直接获取页面加载完毕后的内容,因为PHP是服务器端语言,负责生成HTML页面并发送给客户端。一旦PHP代码生成HTML页面并发送给客户端,它的任务就结束了,无法直接感知客户端页面加载的状态。 不过,可以通过一些其他的方法来实现类似的功能。其中一个常见的方法是使用JavaScript来检测页面加载状态。在页面加载完毕后,通过JavaScript发送一个异步请求给服务器端,请求需要的内容。服务器端可以使用PHP处理这个请求,并返回所需的内容。 具体实现步骤如下: 1. 在页面中嵌入带有JavaScript代码块的HTML文件。 2. 在JavaScript代码块中,使用window.onload事件监听页面加载完成事件。 3. 当页面加载完成后,使用XMLHttpRequest对象发送异步请求给服务器端。 4. 服务器端接收到该请求后,使用PHP代码处理请求,并返回所需的内容。 5. JavaScript代码通过XMLHttpRequest对象接收到服务器端返回的内容,处理并显示在页面上。 需要注意的是,这种方法依赖于客户端的浏览器支持JavaScript,并且需要在页面加载完成后执行相应的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值