β

HTML5文件上传组件的深度剖析

FEX 百度 Web 前端研发部 376 阅读
作者:2betop

前段时间在w3ctech技术交流会中分享了基于 HTML5 技术的文件上传组件,由于ppt携带的信息非常有限,故在此整理成文章分享出来,供感兴趣的同学阅读。

HTML VS FLASH

对于文件上传,相信还有不少同学还停留在FLASH时代,其实现在 HTML5 不仅可以实现文件上传,而且可以做得更好。

以下是对 HTML5 与 FLASH 就文件上传方面的功能调研测试得出的结果。

功能描述 FLASH HTML5
文件多选
格式过滤
拖拽(文件 & 文件夹)
截屏粘贴
Cookie & Session
文件内容读取 ✓ 快150%
图片预览&裁剪 ✓ 快200%
文件上传 ✓ 快10%
进度跟踪 ✓ 更加精准

PS: 截屏粘贴是指,如果剪切板里面存在图片数据,是可以通过 CTRL + V 将此图片作为文件添加到文件上传组件中的。让剪切板中有图片数据有很多方式:截屏软件(如QQ截屏),浏览器中右击图片点击复制,QQ聊天软件中复制图片...

可以看出,采用 HTML5 技术与传统的 FLASH 技术相比,能实现的功能更多且性能优势特别明显。

更多调研细节请移步到这里

虽然 HTML5 优势非常明显,但是如果目前支持 HTML5 的浏览器占比情况不理想,采用 HTML5 技术的文件上传还是不能带来足够的收益!

让我们先来看看由 TNW 提供的2014年3月份全球浏览器占比图。

通过浏览器占比可以推算出,目前支持 HTML5 的浏览器占比高达64.5%,加上 HTML5 有如此大的优势,看来完全没有理由拒绝采用 HTML5 来实现文件上传了。

但是还有35%的浏览器不支持 HTML5,怎么办?

为了考虑最大的兼容性,目前WebUploader同时实现了 HTML5 和 FLASH 两套运行时,在不支持 HTML5 的浏览器里面自动切换成 FLASH 方式上传,这样的好处是,既能在条件允许的情况保证 HTML5 发挥出其高效的优势,又能在不支持 HTML5 的浏览器里面保证能正常运行。

如何优化文件上传性能?

对于文件上传性能优化,可以从两个方面来着手,即上传前的优化和上传过程中的优化。

上传前的优化

主要有两个思路。

基于这两个思路,我们尝试了以下几种方案。

上传过程中优化

主要采用并发与分块,以下将细说这两个方案。

并发上传

采用此方案主要是源于单一请求无法让网络达到饱和,于是我们来尝试采用并发方式看能否提高总体文件上传速度。

以下是通过测试20个1M的文件在不同的并发数下得到的总体上传时间对比图。

并发对比图

很明显,并发数越多速度越快!

但是,并发数越多,给服务端带来的压力也越大,如何去选择一个合适的并发数呢?

主要可以从三方面去考虑。

  1. 并发数越多,服务端压力越大,所以选择并发数不能太大!
  2. 同时每个浏览器都有固定的最大并发数限制,所以选择并发数不能超出这个值。
  3. 从上面的图标可以看出,并发数到了3以后,收益开始渐渐不明显。

如是,最佳的并发数应该是3。

PS: 以下是常用浏览器的最大并发数信息。根据这个表可以说明为什么前面的测试结果,并发数只测试到了6,原因是chrome的最大并发数是6,当并发设置到7的时候,第7个请求是处于等待状态,直到前面某个请求完成,才会开始有进度。

浏览器 HTTP 1.1 HTTP 1.0
IE 6, 7 2 4
IE 8 6 6
Firefox2 2 8
Firefox3 6 6
Safari 3, 4 4 4
Chrome 1, 2 6 ?
Chrome 3 4 4
Chrome 4+ 6 ?

为什么并发会更快?

这里列出了我个人觉得可能的原因。

分块上传

为什么要采用分块上传?

试想一下,如果上传的文件是一个大文件,本来上传时间就相对较久,再加上网络不稳定各种因素影响,容易导致传输中断,用户除了重传整个文件外没有更好的选择。采用分片上传可以很好地解决这个问题。

什么是分片上传?

分块上传,就是把一个大的文件分成若干块,一块一块的传输。如上面的case, 如果传输中断,仅需重传出错的分片,而不需要重传整个文件,大大减少了重传开销。

那么,采用分块上传还有哪些优势?

当然,分块也会有一定的副作用,本来是一个请求,分块后变成了多个请求,自然会带来网络开销。那么具体是个什么的情况呢?

以下是通过测试3个30M的文件在3个并发下调整不同的分片大小得出的总体时间消耗表。

分块对比图

可以看出来,分块越小,时间消耗越大,尤其是分块大小小到256K的时候,时间花费增长特别明显。

那么,如何选择一个合适的分块大小?

主要有三个方面的考虑。

综合这些考虑,推荐的分块大小是2M-5M,具体size根据产品中文件上传的大小分布来定。如果上传的文件大部分是500M以上,很大的文件,建议是5M, 如果相对较小,推荐2M。

断点续传

有了分块上传,其实我们可以实现更多的功能。试想,如果服务端能够把每个已成功上传的分块都记住,客户端可以快速验证,条件选择跳过某个分块,是不是就实现了断点续传?

那么,断点续传能带来哪些好处?

  1. 节省流量,避免上传重复的分块。
  2. 减少用户等待时间。
  3. 可恢复的上传。出现中断,就算浏览器刷新或者是换了台电脑也能恢复到上次中断的位置。

那么现在最关键的问题是如何标识一个分块了。怎样标识让服务端好入库,同时客户端可以快速的计算出来与服务端验证,换句话说就是,如何去找出分块的唯一ID。

之前尝试过文件名+分块编号,或者再加文件大小,文件最后修改时间什么的,都无法保证分块的唯一性。于是还是直接采用 MD5 的方式来序列化文件内容吧,这样就算是文件不同名,只要内容是一致的也会正确地识别出是同一个分块。

那么现在的逻辑就是,每次分块上传前,根据内容 MD5 序列化,得到一个唯一ID,与服务端验证,如果此分块已经存在于服务端,则直接跳过此分块上传,否则上传此分块,成功后,服务端记下此分块ID。

如是,分块上传是不是具有了秒传的功能?既然分块能秒传,那么整个文件是否也可以秒传?

秒传

分块能秒传,整个文件当然也能秒传,关键还是看 MD5 的性能。

md5性能

通过以上测试结果可以看出,如果文件大小在 10M 以内,是可以真正的秒级内完成的,大于这个值时间花费就大于1秒了,比如一个200M的文件 MD5 时间花费需要13秒左右。

但是,即便如此,相比于文件传输时间花费,MD5 的时间花费根本就不算什么。对于类似于百度云,文库这类的产品,在上传一个文件的时候很可能服务端已经存在了此文件,如果多等个几秒钟,能跳过整个文件上传,我觉得是非常划算的。

另外,如果是一次上传多个文件是可以在算法上去优化这个过程的。

参考资料

作者:FEX 百度 Web 前端研发部
原文地址:HTML5文件上传组件的深度剖析, 感谢原作者分享。