关于网页内容加速黑科技的趣谈

数周前,在伦敦 Heathrow 机场等飞机的空闲中,我顺便处理了一些工作上的事情。不经意间发现 Github 在性能方面的一些问题,颇为诧异。通过新 tab 打开的页面,其加载速度竟然比直接点击链接打开的页面要快。

点击链接的同时复制链接并在新的 tab 页中打开。可以看到,尽管先点击的是链接,但渲染更快的却是新 tab 中打开的页面。

有一说一

页面加载的时候,浏览器会接收网络数据流,并将其输出(pipe)给 HTML 解析器,HTML 解析器再将数据输出到文档。这意味着,页面是边加载边渲染的。对于一个 100k 的页面来说,浏览器很可能在接收到 20k 数据的时候就开始渲染出一些可用内容了。

这个伟大又古老的特性,常常被开发者们有意无意地忽略了。多数提高加载性能的建议都归结于一点,即“展示你所拿到的东西” —— 别怕,千万不要傻傻等待一切加载完成之后再去展示内容。

GitHub 当然是关注性能的,所以他们使用服务端渲染。但在同一个 tab 下浏览页面时,他们用 JavaScript 重新实现了导航(navigation)功能,类似下面这样:


  1. // …一堆重新实现浏览器导航功能代码… 
  2. const response = await fetch('page-data.inc'); 
  3. const html = await response.text(); 
  4. document.querySelector('.content').innerHTML = html; 
  5. // …加载更多重新实现导航功能的代码…  

这违反了规则,因为在 page-data.inc 下载完成之前什么事情都没干。而服务端渲染版完全不会这样囤积内容,其内容是流式的,这样就要快得多了。就 Github 的客户端渲染来说,很多 JavaScript 代码完全减慢了渲染过程。

这里我仅仅只是拿 Github 举例子 —— 这种反模式在单页应用中比比皆是。

在页面之内切换内容可能确实有些好处,特别是存在大量脚本的情况下,无需重新执行全部脚本即可更新内容。但我们能否在不放弃流的情况下完成这样的工作呢?我曾经常说 JavaScript 没有办法对流进行解析,但其实还是有的……

<iframe> 和 document.write 大法

iframe 早已跻身圈内最臭黑科技之列。但下面这个办法就使用了 iframe 和 document.write(),这样我们就能将内容以流的形式添加到页面中了。示例如下:


  1. // 创建 iframe: 
  2. const iframe = document.createElement('iframe'); 
  3.  
  4. // 添加到 document 中 (记得隐藏起来): 
  5. iframe.style.display = 'none'; 
  6. document.body.appendChild(iframe); 
  7.  
  8. // 等待 iframe 加载: 
  9. iframe.onload = () => { 
  10.   // 忽略其他 onload 操作: 
  11.   iframe.onload = null; 
  12.   // 添加一个虚拟标签: 
  13.   iframe.contentDocument.write('<streaming-element>'); 
  14.   // 引用该元素: 
  15.   const streamingElement = iframe.contentDocument.querySelector('streaming-element'); 
  16.   // 将该元素从 iframe 中取出,并添加到文档中: 
  17.   document.body.appendChild(streamingElement); 
  18.   // 写入一些内容 —— 这里应该是异步的: 
  19.   iframe.contentDocument.write('<p>Hello!</p>'); 
  20.   // 继续写入内容,直到完成: 
  21.   iframe.contentDocument.write('</streaming-element>'); 
  22.   iframe.contentDocument.close(); 
  23. }; 
  24.  
  25. //  iframe 初始化 
  26. iframe.src = '';  

虽然 Hello! 是写到 iframe 中的,但它却出现在了父级的 document 中!这是因为解析器维护了一个 敞开元素栈(stack of open elements),新创建的元素会被压入栈中。就算我们把 <streaming-element/> 元素移出到 iframe 外面也不影响,就是这么任性。

此外,这种技术处理起 HTML 来,要比 innerHTML 更接近标准的页面加载解析器。尤其是脚本依然会被下载,并在父级文档的上下文中执行 —— 只是在 Firefox 中完全不会执行,但我认为这是个 bug更新: 其实脚本根本不应该执行(感谢 Simon Pieters 指出这一点),但 Edge、Safari、Chrome 都这么干。

接下来我们只需要从服务端获取 HTML 数据流,每当一个部分的数据到达的时候,就调用 iframe.contentDocument.write()。流式传输和 fetch() 搭配起来会更好,但为了支持 Safari,我们还是使用 XHR 来 hack 一下吧。

我已经写好了一个 demo,可以拿来和 Github 进行对比。下面是在 3G 网络下的测试结果:

点击这里查看原始测试数据

使用 iframe 进行流式渲染,页面加载速度提高了 1.5 s。头像也提前半秒钟加载完成 —— 流式渲染意味着浏览器可以更早发现它们,并与内容一起并行下载。

上面的方法对 Github 来说还是有效的,因为它的服务器返回的是 HTML。如果你使用的是框架,由框架自己管理 DOM 的展示,那可能就麻烦一些了。这种情况下可以看看下面这个次优选项:

换行符分隔的 JSON

许多网站使用 JSON 驱动动态内容。何其不幸,JSON 并不是一种对流友好的格式。尽管也有流式 JSON 解析器,可用起来却并不那么简单。

所以与其传输下面这样一大块 JSON 数据:


  1.   "Comments": [ 
  2.     {"author": "Alex", "body": "…"}, 
  3.     {"author": "Jake", "body": "…"} 
  4.   ] 
  5. }  

还不如像下面这样一行输出一个 JSON 对象:


  1. {"author": "Alex", "body": "…"} 
  2.  
  3. {"author": "Jake", "body": "…"}  

这种被称为 “换行符分隔的 JSON” 是有标准的:ndjson。给上面的内容写一个解析器就要简单多了。到了 2017 年,我们也许可以使用一系列组合变换流(composable transform streams)来描述(译者注:本文写作于 2016 年 12 月):


  1. // 在 2017 年的某个时候可能会是这样: 
  2. const response = await fetch('comments.ndjson'); 
  3. const comments = response.body 
  4.   // 从字节到文本: 
  5.   .pipeThrough(new TextDecoder()) 
  6.   // 一直缓冲,直到遇到换行符: 
  7.   .pipeThrough(splitStream('\n')) 
  8.   // 将内容块解析为JSON: 
  9.   .pipeThrough(parseJSON()); 
  10.  
  11. for await (const comment of comments) { 
  12.   // 处理每条评论,并将其添加到页面: 
  13.   // (不管你使用的是什么模板或虚拟 DOM) 
  14.   addCommentToPage(comment); 
  15. }  

在上面的代码中,splitStream 和 parseJSON 是 可复用变换流(reusable transform streams)。与此同时,为了实现最大程度的兼容,我们可以使用 XHR 进行 hack。

我再次新建了一个对比的 demo,下面是 3G 网络下的结果:

点击这里查看原始测试数据

与常规 JSON 相比,ND-JSON 提前 1.5s 将内容渲染到页面上,尽管速度不如 iframe 方法那么快。在创建元素之前,必须等待完整的 JSON 对象出现。如果你的 JSON 文件体量巨大,可能会陷入对流的企盼之中。

单页应用?别着急

如前所述,Github 使用了大量的代码,然而却带来这样的性能问题。在客户端重新实现导航功能是困难的,如果你需要改变页面中的大块内容,这么做有可能并不值得。

可以拿我们的尝试与简单浏览器导航进行对比:

点击这里查看原始测试数据

打开一个简单的没有使用 JavaScript 浏览器导航的服务端渲染页面的速度差不多是一样的。但除去评论列表,测试页面实在太过简单。如果在不同页面之间存在有大量重复的复杂内容(主要是指可怕的广告脚本),结果可能因实际情况而有差异,但一定要记得进行测试!很可能你编写了一大堆代码,然而只能带来少的可怜的提升,甚至还可能减慢速度。  

原文发布时间为:2017-10-13

本文作者:Jake

本文来自合作伙伴“51CTO”,了解相关信息可以关注。

时间: 2024-10-03 10:09:10

关于网页内容加速黑科技的趣谈的相关文章

浅谈阿里云PCDN原理及接入 几行代码能节省上百万的黑科技到底是什么?

早在今年6月,阿里云已经发布了有一款黑科技产品--PCDN,它是以P2P技术为基础,通过挖掘利用边缘网络海量碎片化闲置资源而构建的低成本高品质内容分发网络服务,非常适用于视频点播.直播.大文件下载等业务场景.自从上线开始就得到了行业的关注,很多用户也在第一时间的申请了试用. 距离上线时隔五个月,不少用户已经成功接入并且上线运行了一段时间.其中绝大部分客户反馈加速效果得到优化,视频首播时间.流畅率等核心性能指标均有提升.与此同时,每月的CDN费用得到了有效缩减,平均降幅超过40%,真正做到了质量提

分析加速引擎黑科技 - LLVM、列存、多核并行、算子复用 大联姻 - 一起来开启PostgreSQL的百宝箱

标签 PostgreSQL , LLVM , OLAP , 列存储 , IMCS , cstore , column storage , Code Gen , 数据分析 背景 随着移动互联网的发展,数据爆炸性增长,企业对数据产生价值的渴望越来越多. 比如很多APP中会埋点(已经不是什么秘密),以此收集用户的行为数据,用户的位置变化,上了什么网站,浏览了哪些网页,和什么人聊天. 又比如汽车类的应用,汽车的轨迹,油耗,停留的时间,最喜欢去的商圈等. 金融方面,用户的付费行为,和哪个商铺发生的交易,交

智能投顾十大趣谈,基金从业者该不该恐慌?

  雷锋网(公众号:雷锋网)按:此文授权转载自公众号浩哥说,作者是松禾远望基金合伙人田鸿飞. 趣谈一.银行和基金从业人员最恐慌的是未来饭碗会否不保 波士顿是美国资管行业的重镇.2016年我在波士顿和做基金管理的校友交流中发现,受到金融科技发展的影响,他们对未来有些悲观,认为饭碗在未来某一天也许就没了.很多在银行工作的朋友同样焦虑. 我的观点,大量易标准化.重复性.没技术含量.不具独创性的工作肯定会被裁掉.从基金行业来说,首先后台最容易被替代,因为都是成本.清算.交收.估值类工作,以前需要多人忙碌

揭秘中韩足球大赛背后的无线“黑科技”

昨日中韩大赛,今天我们想谈谈赛场流畅网络背后的事儿.在贺龙体育场里部署Wi-Fi网络是不是装几百台AP,顶多再接到AC上统一管理这么简单呢? 先问一个问题:你有没有试过上百人同时在你耳边"嗡嗡翁"的情况下,给女朋友打电话呢? 可以想象,你一定听不清那头女朋友说什么,你的女朋友也听不清楚你在说什么,这属于无法友好沟通~~ 同样的道理,锐捷无线应用了什么"黑科技",保证贺龙体育场里的几百台AP.数万部手机相互之间干扰最小,从而能够同时流畅上网呢? 正确答案:1.高密度部

用电线来传网络信号的黑科技?AirGig究竟是什么

在已经结束的MWC 2017大会上,人们讨论了作为4G后继者的5G.照理说5G相对4G当然能够带来更好的网络体验,但问题在于它作为一个业界的技术标准,根本还不存在.没有人知道5G是什么,更别提怎么实现,什么时候到来了.正因为如此AT&T的工程师们提出了另外一种技术,旨在带来更高速的宽带,更强的信号质量,甚至能够遍及那些网络欠发达的区域. 什么是AirGig? 不需要专门的线路或信号站,可以支持几乎无处不在的超快Wi-Fi,这就是AirGig.那么,AirGig到底是什么? 有一种说法认为AirG

用电线来传网络信号的黑科技?详谈AirGig技术

在已经结束的MWC 2017大会上,人们讨论了作为4G后继者的5G.照理说5G相对4G当然能够带来更好的网络体验,但问题在于它作为一个业界的技术标准,根本还不存在.没有人知道5G是什么,更别提怎么实现,什么时候到来了. 正因为如此,AT&T的工程师们提出了另外一种技术,旨在带来更高速的宽带,更强的信号质量,甚至能够遍及那些网络欠发达的区域.不需要专门的线路或信号站,可以支持几乎无处不在的超快Wi-Fi,这就是AirGig.那么,AirGig到底是什么? 有一种说法认为AirGig是一种"

物联网黑科技:不耗电的新wifi技术

国外媒体报道,美国华盛顿大学电子工程学院的学生们日前研发出了一种全新的WiFi技术,其最大特点是能耗不到当前WiFi的万分之一. Gartner去年公布的新兴技术周期图显示,2016年IoT成为最被期待的新兴技术,与之相关的IOT平台同样受到强烈的关注,未来5到10年IoT技术将趋于成熟.到2020年联网设备的总数将达到甚至超过500亿,物联网将把家庭中的很多设备囊括进来,其中小到智能恒温器,可穿戴设备名大到智能电冰箱-- 物联网黑科技:不耗电的新wifi技术 而电池有时候是移动设备与传感器的祸

通信黑科技:窄带物联网NB- IoT激活物联网

最近两个月来,通信板块的新技术正频频"引爆"市场.不仅窄带物联网NB- IoT激活了物联网板块,量子通信板块也呈现逆势拉升态势. 据记者了解,资金下一步或将盯上智能网联汽车LTE-V.在业内人士看来,顺应社会发展趋势.受到政策强力推进,并且有众多业内巨头重金参与的智能驾驶领域,有望在LTE-V成为中国技术路线标准后被激活,也吸引机构强力布局车联网领域. 通信黑科技频繁"引爆"市场 6月份以来,通信领域的"黑科技"开始受到市场追捧,新技术标准或者创

Gartner预测2017年十大黑科技 人工智能、物联网列其中

Gartner公司最近公布了2017年具备战略意义的重大科技发展趋势.这十大技术趋势可以总结概括为:以智能为中心,通过数字化实现万物互联.Gartner预计,这些趋势在未来五年内迅速增长.高度波动.预计达到临界点. Gartner副总裁兼研究员David Cearley说,"这十大趋势中,前三个趋势体现了'智能无处不在',以将智能物理和基于软件的系统应用于机器学习和自适应.接下来的三个趋势聚焦数字世界,物理和数字世界日益纠缠.而最后四个趋势则着眼于智能数字网络所需的平台和服务网络."