更新时间:2022-09-12 07:47:55
对于文件上传,相信还有不少同学还停留在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的文件在不同的并发数下得到的总体上传时间对比图。
很明显,并发数越多速度越快!
但是,并发数越多,给服务端带来的压力也越大,如何去选择一个合适的并发数呢?
主要可以从三方面去考虑。
如是,***的并发数应该是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 ?
为什么并发会更快?
这里列出了我个人觉得可能的原因。
左边是非并发的情况,右边为采用并发的情况。可以看出,当不采用并发的时候,每个文件上传请求前都会进行options请求验证,而并发的时候,三个文件上传请求共用了一个opions请求。
为什么要采用分块上传?
试想一下,如果上传的文件是一个大文件,本来上传时间就相对较久,再加上网络不稳定各种因素影响,容易导致传输中断,用户除了重传整个文件外没有更好的选择。采用分片上传可以很好地解决这个问题。
什么是分片上传?
分块上传,就是把一个大的文件分成若干块,一块一块的传输。如上面的case, 如果传输中断,仅需重传出错的分片,而不需要重传整个文件,大大减少了重传开销。
那么,采用分块上传还有哪些优势?
当然,分块也会有一定的副作用,本来是一个请求,分块后变成了多个请求,自然会带来网络开销。那么具体是个什么的情况呢?
以下是通过测试3个30M的文件在3个并发下调整不同的分片大小得出的总体时间消耗表。
可以看出来,分块越小,时间消耗越大,尤其是分块大小小到256K的时候,时间花费增长特别明显。
那么,如何选择一个合适的分块大小?
主要有三个方面的考虑。
综合这些考虑,推荐的分块大小是2M-5M,具体size根据产品中文件上传的大小分布来定。如果上传的文件大部分是500M以上,很大的文件,建议是5M, 如果相对较小,推荐2M。
有了分块上传,其实我们可以实现更多的功能。试想,如果服务端能够把每个已成功上传的分块都记住,客户端可以快速验证,条件选择跳过某个分块,是不是就实现了断点续传?
那么,断点续传能带来哪些好处?
那么现在最关键的问题是如何标识一个分块了。怎样标识让服务端好入库,同时客户端可以快速的计算出来与服务端验证,换句话说就是,如何去找出分块的唯一ID。
之前尝试过文件名+分块编号,或者再加文件大小,文件最后修改时间什么的,都无法保证分块的唯一性。于是还是直接采用 MD5 的方式来序列化文件内容吧,这样就算是文件不同名,只要内容是一致的也会正确地识别出是同一个分块。
那么现在的逻辑就是,每次分块上传前,根据内容 MD5 序列化,得到一个唯一ID,与服务端验证,如果此分块已经存在于服务端,则直接跳过此分块上传,否则上传此分块,成功后,服务端记下此分块ID。
如是,分块上传是不是具有了秒传的功能?既然分块能秒传,那么整个文件是否也可以秒传?
分块能秒传,整个文件当然也能秒传,关键还是看 MD5 的性能。
通过以上测试结果可以看出,如果文件大小在 10M 以内,是可以真正的秒级内完成的,大于这个值时间花费就大于1秒了,比如一个200M的文件 MD5 时间花费需要13秒左右。
但是,即便如此,相比于文件传输时间花费,MD5 的时间花费根本就不算什么。对于类似于百度云,文库这类的产品,在上传一个文件的时候很可能服务端已经存在了此文件,如果多等个几秒钟,能跳过整个文件上传,我觉得是非常划算的。
另外,如果是一次上传多个文件是可以在算法上去优化这个过程的。