计算机教程

页面白屏与瀑布流分析方法必赢娱乐棋牌

14 3月 , 2019  

页面白屏与瀑布流分析方法

2015/12/03 · HTML5,
JavaScript · 1
评论
·
瀑布流,
白屏

原文出处: 淘宝前端团队(FED)-
妙净
   

必赢娱乐棋牌 1

无线页面的开发在我们的日常工作中越来越重要,无线的性能也是我们需要重点关注的,而加载的性能又是无线性能中的一个重要问题。那么,今天我们一起来看下如何去评估、测试无线页面的加载性能。

为了方便分析页面的加载过程,这里将网络设置成最慢的
GPRS,并将加载过程录制下来,通常你可以通过 Chrome 自带的 timeline, 勾选
screenhot,可以得到详尽的过程,如下图:

必赢娱乐棋牌 2

这里为了和请求一一清晰对照,用额外录屏工具( licecap
)录制下来。下文以淘宝双 11 男装分会场的预发页面作为测试,录制 结果
gif

如下,录制的 FPS 为 8。

帧分析如下:

第一帧:重新刷新页面,发起 HTML 请求,中间完整页面是刷新前的,请无视之。

必赢娱乐棋牌 3

终于等到第 7 帧,HTML 加载并解析完成,发出页面中的请求,同时 CSS/JS
的地址都收敛在 //g.alicdn.com 同一个域名下, Chrome 下 HTTP 1.1
协议下一个域名下支持 6 个并发。

1 年前,PC 上以前还有多个域名分区(img01-04.tbcdn.cn),PC
上首屏图片多,这样可并发更多,但更多的域名引入,也加大了域名解析的成本,权衡之下淘宝之前图片域名选择了
4 个;后来集团经过轰轰烈烈的 HTTPS 改造,图片推荐收敛到 gw.alicdn.com
;手淘下现在使用 SPDY + HTTPS,相比 HTTP 1.1 ,更安全且可以多路复用。

必赢娱乐棋牌 4

到第 20 帧, CSS 下载完,DOM 和
CSSOM
都准备 OK 了,页面则开始渲染了;这是在 Chrome 下面看到的情况,但在 iOS
上并非如此,它需要 JS 加载并执行完才渲染页面。

必赢娱乐棋牌 5

第 21 帧,紧接着,CSS 中的背景图开始相继渲染,可见 CSS
中渲染图片也是有点耗时的。

必赢娱乐棋牌 6

第 23 帧,前面并行下载的 JS 都下载完,也开始执行了,看“疯狂 top 榜”是 JS
抽取出来的。同时 aplus 请求也开始请求,这是个 getScript
的异步请求,可见异步请求真没有阻塞页面的渲染。

必赢娱乐棋牌 7

第 25 帧,JS 还在继续执行,第一张图片是 JS 根据当前
dpr、强弱网络、设备宽度等算出最适合的图片开始加载这张大 banner
了,并且开始发送数据请求了。

必赢娱乐棋牌 8

到 27 帧,终于数据请求回来了,并且把文字和图片渲染到页面上了。

必赢娱乐棋牌 9

然后下一帧 28,开始请求商品图片了。

必赢娱乐棋牌 10

到 45 帧,6 个图片都在并发请求,同上 gw.alicdn.com 同一个域下并发 6
个请求。但首屏除了大图外只有 4 张图(2 张商家 logo 被底部 bar
挡住了),这里发出了 6 个图片请求,可见这个页面的懒加载的 buffer
值可以设置得更小。

必赢娱乐棋牌 11

从 28 帧到 50 帧,经历了很长的时间,第一张图片终于显示出来了。另外看到
aplus_v2 执行完后,又发起了 spm 等请求,后面 3 个请求(
aplus-proxy.html/isproxy.js/m.gif )还是串行的。

必赢娱乐棋牌 12

最后到第 61 帧,终于所有的图片都加载完了,最后看下,最后下载完的是大
banner 图,因为有 46.9k ,这张图的大小可能成为此页面的 load
时间的关键;如果这张图没有这么大,最后下载完的可能是用于埋点的 m.gif。

必赢娱乐棋牌 13

从上面整个请求的瀑布流分析下来,我们来回顾下页面的关键时间点:

script inject 和 async

JavaScript

<!– BAD –> <script
src=”//g.alicdn.com/large.js”></script> <!– GOOD –>
<script> var script = document.createElement(‘script’); script.src
= “//g.alicdn.com/large.js”;
document.getElementsByTagName(‘head’)[0].appendChild(script);
</script>

1
2
3
4
5
6
7
8
9
  <!– BAD –>
<script src="//g.alicdn.com/large.js"></script>
 
<!– GOOD –>
<script>
  var script = document.createElement(‘script’);
  script.src = "//g.alicdn.com/large.js";
  document.getElementsByTagName(‘head’)[0].appendChild(script);
</script>

我们通常用这种 inject script 的方式来异步加载文件,特别是以前
Sea.jsKISSY 的盛行时,出现大量使用$.use
来加载页面入口文件。这种方式和 async 的一样都能异步化
JS,不阻塞页面渲染。但真的是最快的吗?

一个常见的页面如下:一个 CSS,两个异步的 JS

JS 使用 script inject
的方式测试结果如下,DEMO

必赢娱乐棋牌 14

JS 使用 async 的方式测试结果如下,
DEMO

必赢娱乐棋牌 15

对比结果发现,通过 “ 的方式的 JS 可以和 CSS 并发下载,这样整个页面 load
时间变得更短,JS
更快执行完,这样页面的交互或数据等可以更快更新。为什么呢?因为浏览器有类似
preload
scanner

的功能,在 HTML 解析时就可以提前并发去下载 JS 文件,如果把 JS
的文件隐藏在 JS 逻辑中,浏览器就没这么智能发现了。

也许大家会说,现在 CSS/JS
都预加载到客户端了,怎么加载不重要。但页面有可能分享出去也有可能运行在浏览器中,也有可能预加载失效。

综合上面 async 和 defer,推荐以下用法。

JavaScript

<!– 现代浏览器用 ‘async’, ie9-用 ‘defer’ –> <script
src=”//g.alicdn.com/alilog/mlog/aplus_wap.js” async
defer></script>

1
2
<!– 现代浏览器用 ‘async’, ie9-用 ‘defer’ –>
<script src="//g.alicdn.com/alilog/mlog/aplus_wap.js" async defer></script>

其实现在无线站点 aplus.js 可以完全用这种方式引入,既不会阻塞 DOM
CSSOM,也不会延长整个页面 onLoad 时间,而不是原来的 PC 上的
script inject方式。

如果 aplus.js 在 PC 上这么用,IE 8/IE 9 应用的是 defer
属性,不会阻塞页面渲染,但是这个 JS 需要执行完后才触发
domReady(DOMContentLoaded)事件,故在 IE 8/IE 9 下可能会影响 domReady
的时间。

重要内容可见时间

重要内容可见,这里可以认为是商品数据,商品数据可见要等 JS
执行完并且异步请求发送出去回来后才可见。

TMS\[1\]
的异步请求大多走招商数据平台(TCE\[2\])的接口,测试其单个请求在真机的耗时约为
110ms(样本较少,未大量测试)。

必赢娱乐棋牌,几种异步加载方式测试

  • A. head script: 即普通的将 JS 放在 head 中或放在 body
    中间:DEMO 地址
  • B. bottom script: 即常规的优化策略,JS 放body的底部:DEMO
    地址
  • C. document.write: 以前 PC 优化少用的一种异步加载 JS 的策略:DEMO
    地址
JavaScript

function injectWrite(src){ document.write('&lt;script src="' + src +
'"&gt;&lt;/sc' + 'ript&gt;'); }

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5a721bbc827ff070447677-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a721bbc827ff070447677-2">
2
</div>
<div class="crayon-num" data-line="crayon-5a721bbc827ff070447677-3">
3
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5a721bbc827ff070447677-1" class="crayon-line">
function injectWrite(src){
</div>
<div id="crayon-5a721bbc827ff070447677-2" class="crayon-line crayon-striped-line">
  document.write('&lt;script src=&quot;' + src + '&quot;&gt;&lt;/sc' + 'ript&gt;');
</div>
<div id="crayon-5a721bbc827ff070447677-3" class="crayon-line">
}
</div>
</div></td>
</tr>
</tbody>
</table>
  • D. getScript: 形如以下,也是 KISSY
    内部的getScript函数的简易实现:DEMO
    地址
JavaScript

&lt;script&gt; var script = document.createElement('script');
script.src = "//g.tbcdn.com/xx.js";
document.getElementsByTagName('head')\[0\].appendChild(script);
&lt;/script&gt;

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5a721bbc82807359027480-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a721bbc82807359027480-2">
2
</div>
<div class="crayon-num" data-line="crayon-5a721bbc82807359027480-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a721bbc82807359027480-4">
4
</div>
<div class="crayon-num" data-line="crayon-5a721bbc82807359027480-5">
5
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5a721bbc82807359027480-1" class="crayon-line">
&lt;script&gt;
</div>
<div id="crayon-5a721bbc82807359027480-2" class="crayon-line crayon-striped-line">
  var script = document.createElement('script');
</div>
<div id="crayon-5a721bbc82807359027480-3" class="crayon-line">
  script.src = &quot;//g.tbcdn.com/xx.js&quot;;
</div>
<div id="crayon-5a721bbc82807359027480-4" class="crayon-line crayon-striped-line">
  document.getElementsByTagName('head')[0].appendChild(script);
</div>
<div id="crayon-5a721bbc82807359027480-5" class="crayon-line">
&lt;/script&gt;
</div>
</div></td>
</tr>
</tbody>
</table>

结束语

以上在 Chrome 上的测试,但实际在手淘里面,在
spdy、https、离线包内置资源等的影响下,它的瀑布流还是这样的吗?

原文出处: 淘宝前端团队(FED)-
妙净
   

注:

  • [1]: TMS 为淘宝内部运营活动系统。
  • [2]: TCE 为淘宝内部数据接口系统。
  • [3]: Cake 为淘宝内部前端开发套件。

 

1 赞 收藏 1
评论

必赢娱乐棋牌 16

didFinishLoad 到底什么时候触发

didFinishLoad 是 native 定义的事件,该事件触发时手淘 loading
菊花消失,并且 windvane 中的发出请求不再收集,也就是 native 统计出的
pageLoad 时间。在用户数据平台看到的瀑布流请求,就是在 didFinishLoad
触发前收集到的所有请求。

必赢娱乐棋牌 17

经过上方测试,客户端的 didFinisheLoad 事件的触发和 JS 中的
domReady(DOMContentLoaded)和 onLoad 触发没有任何关联。可能在 domReady
之前或之后,也可能在 onLoad 之前或之后。

那它到底是什么时候触发呢? iOS
官方文档

是 Sent after a web view finishes loading a frame。
结合收集的用户请求和测试,didFinishLoad
是在连续发起的请求结束之后触发,监听一段时间内无请求则触发。

所以经常会看到 data_sufei 这个 JS
文件,在有些用户的瀑布流里面有,在有些用户的又没有。原因是这个 JS 是
aplus_wap.js 故意 setTimeout 1s 后发出的,如果页面在 1s
前所有的请求都发完了则触发 didFinishLoad,后面的 data_sufei.js
的时间就不算到 pageLoad 的时间;反之如果接近 1s
页面还有图片等请求还在发,则 data_sufei.js 的时间也会被算到里面。

因此在 JS 中用 setTimeout 来延迟发送请求也有可能会影响 didFinishLoad
的时间,建议 setTimeout 的时间设置得更长一点,如 3s。

白屏时间和补救方法

在 Wi-Fi 下,这 60
多帧的过程一眨眼就过去了,但在弱网络下,如这里最极端的网络 GPRS
下,整个首屏含图片全部加载完成需要 41.25s。当然这 40
多秒过程能尽早出现内容,并渐进和谐地呈现出来是比较好的。

男装频道是修改过后的,对比之前的未处理的猜你喜欢页面,出现长时间的白屏,如下:

必赢娱乐棋牌 18

以下为本地生活修复后的效果:

必赢娱乐棋牌 19

白屏处理只要稍微注意下就可以,修复的方便也简单,尽量同步输出,异步输出请尽量
mock 出现在首屏的模板。如果是基于 Cake\[3\]
工具开发的,也可以直接用首屏填充伪标签。

参考资料

页面可见时间

在第 20 帧页面可见,CSS 完成之后,当然前提是这里没有外链 JS
在页面中间因为网络请求严重阻塞页面。这里分析的仅仅是 Chrome
浏览器,不是真机,在 iOS 上,就算 JS 在底部,直接 <script src=”xx”> 也是会阻塞页面。可以通过加
async 属性,通知渲染引擎这是不影响页面渲染的 JS,可以异步加载,iOS
下添加此属性可实现和 Android 或 PC Chrome 一样的效果。

如何选择 async 和 defer

  • defer 可以保证执行顺序,async 不行【注:hack】
  • async 可以提前触发 domReadydefer 不行【注:Firefox 的
    defer 也可以提前触发 domready
  • defer 在 iOS 和部分 Android 下依然阻塞渲染,白屏时间长。
  • 当 script 同时加 asyncdefer
    属性时,后者不起作用,浏览器行为由 async 属性决定。
  • asyncdefer 的兼容性不一致,好在 asyncdefer
    无线端基本都支持,async 不支持 IE 9-。
    async 兼容性 defer
    兼容性

defer :延迟

HTML 4.0 规范,其作用是,告诉浏览器,等到 DOM+CSSOM
渲染完成,再执行指定脚本。

JavaScript

<script defer src=”xx.js”></script>

1
<script defer src="xx.js"></script>
  • 浏览器开始解析 HTML 网页
  • 解析过程中,发现带有 defer 属性的 script 标签
  • 浏览器继续往下解析 HTML 网页,解析完就渲染到页面上,同时并行下载
    script 标签中的外部脚本
  • 浏览器完成解析 HTML 网页,此时再执行下载的脚本,完成后触发
    DOMContentLoaded

下载的脚本文件在 DOMContentLoaded
事件触发前执行(即刚刚读取完标签),而且可以保证执行顺序就是它们在页面上出现的顺序。所以
添加 defer 属性后,domReady
的时间并没有提前,但它可以让页面更快显示出来。

将放在页面上方的 script 加 defer,在 PC Chrome 下其效果相当于 把这个
script 放在底部,页面会先显示。 但对 iOS Safari 和 iOS WebView 加 defer
和 script 放底部一样都是长时间白屏。


相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图