写在前面
每次想写点东西, 但总是觉得心中有千万种骚操作, 就是手跟不上大脑. 别说了又要超鬼被举报了.
今天还是决定整理下最近的笔记了. 先从 JsBridge 通信耗时测试开始吧. 下面统称 JsB.
正文
之前 hybrid 项目中遇到过一个卡顿问题, 现象是当 JsB 传递数据越大时页面就越容易出现卡顿. 一时间以为是原生部分 因, 于是通过断点发现, 其实卡顿发生在原生接受到 JsB 消息之前, 也就是说是在 H5 部分或者 JsB 处理部分, 由于自己前端刚入门, 还特意去咨询项目中的前端同事, 可能是问题说的不清楚, 最终估计是以为我在给他找问题, 结果就直接说前端只有业务不会造成卡顿. [图片]
所以让我想起了那句话, Talk is cheap.show me the code.
JsB 通信的三个部分, 先看看 JSB 消息传递的调用顺序.
Native 调 JS
JS 调 Native
图片引用自 https://www.jianshu.com/p/fce3e2f9cabc 上图为安卓的调用顺序. iOS 的其实也没什么差别, 只是对应的原生接口名称不一样而. webviewJavaScriptBridge 原理图. PNG
图画的很丑, 将就看吧.
加入埋点
从上图看到各个部分的调用顺序. 所以, 我们先看看 JS 调 Native 的耗时.
JS 部分的时间
onclick() 到 JsB 的 doSend() 方法, 因为这部分都是 JS 代码, 只要在 onclick() 时给 Windows 对象加一个属性 Windows.JSTime 记录触发 onclick() 的瞬时间, 然后再 JsB 的 doSend() 函数中当前时间减去 Windows.JSTime 就是 JS 部分的时间. JsB 部分时间
doSend() 到原生接受到第一条消息也就是触发 webview 的 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler (本人用的 WKWebview, 如果是 UIWebview 自己找下回调函数)
- - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
- if (webView != _webView) { return; }
- NSURL *url = navigationAction.request.URL;
- __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;
- if ([_base isWebViewJavascriptBridgeURL:url]) {
- if ([_base isBridgeLoadedURL:url]) {
- [_base injectJavascriptFile];
- } else if ([_base isQueueMessageURL:url]) {
- [self WKFlushMessageQueue];
- } else {
- [_base logUnkownMessage:url];
- }
- decisionHandler(WKNavigationActionPolicyCancel);
- return;
- }
- if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:decisionHandler:)]) {
- [_webViewDelegate webView:webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler];
- } else {
- decisionHandler(WKNavigationActionPolicyAllow);
- }
- }
但是我们查看 WebViewJavascriptBridge 源码发现, 在触发原生回调后, webview 还是继续调 JsB 的 WebViewJavascriptBridge._fetchQueue(). 所以 JsB 部分的时间, 只需要在 doSend() 给 Windows 添加一个埋点 Windows.JsBTime, 然后在_fetchQueue()return 的前面一行获取瞬时时间减去 Windows.JsBTime 就是 JsB 的消耗时间啦.
原生部分
部分就忽略了, 使用 CFAbsoluteTimeGetCurrent() 做代码执行时间测试相对更加准确.
来源: https://juejin.im/post/5bd97d5be51d45684b1eac5b