首先复习一下Base64的概念,Base64就是一种基于64个可打印字符来表示二进制数据的方法,编码过程是从二进制数据到字符串的过程,在web应用中我们经常用它来做啥呢——传输图片数据。HTML中,img的src和css样式的background-image都可以接受base64字符串,从而在页面上渲染出对应的图片。正是基于浏览器的这项能力,很多开发者提出了将多张图片转换为base64字符串,放进css样式文件中的“优化方式”,这样做的目的只有一个——减少HTTP请求数。但实际上,在如今的应用开发中,这种做法大多数情况是“负优化”效果,接下来让我们细数base64 Url的“罪状”:
一、让css文件的体积失去控制
当你把图片转换为base64字符串之后,字符串的体积一般会比原图更大,一般会多出接近3成的大小,如果你一个页面中有20张平均大小为50kb的图片,转它们为base64后,你的css文件将可能增大1.2mb的大小,这样将严重阻碍浏览器的关键渲染路径:
css文件本身就是渲染阻塞资源,浏览器首次加载时如果没有全部下载和解析完css内容就无法进行渲染树的构建,而base64的嵌入则是雪上加霜,这将把原先浏览器可以进行优化的图片异步加载,变成首屏渲染的阻塞和延迟。
或许有人会说,webpack的url-loader可以根据图片大小决定是否转为base64(一般是小于10kb的图片),但你也应该担心如果页面中有100张小于10kb的图片时,会给css文件增加多少体积。
二、让浏览器的资源缓存策略功亏一篑
假设你的base64Url会被你的应用多次复用,本来浏览器可以直接从本地缓存取出的图片,换成base64Url,将造成应用中多个页面重复下载1.3倍大小的文本,假设一张图片是100kb大小,被你的应用使用了10次,那么造成的流量浪费将是:(100 1.3 10) - 100 = 1200kb。
三、低版本浏览器的兼容问题
这是比较次要的问题,dataurl在低版本IE浏览器,比如IE8及以下的浏览器,会有兼容性问题,详细情况可以参考这篇文章。
四、不利于开发者工具调试与查看
无论哪张图片,看上去都是一堆没有意义的字符串,光看代码无法知道原图是哪张,不利于某些情况下的比对。
说了这么多,有人可能不服气,既然这种方案缺点这么多,为啥它会从以前就被广泛使用呢?这要从早期的http协议特性说起,在http1.1之前,http协议尚未实现keep-alive,也就是每一次请求,都必须走三次握手四次挥手去建立连接,连接完又丢弃无法复用,而即使是到了http1.1的时代,keep-alive可以保证tcp的长连接,不需要多次重新建立,但由于http1.1是基于文本分割的协议,所以消息是串行的,必须有序地逐个解析,所以在这种请求“昂贵”,且早期图片体积并不是特别大,用户对网页的响应速度和体验要求也不是很高的各种前提结合下,减少图片资源的请求数是可以理解的。
但是,在越来越多网站支持http2.0的前提下,这些都不是问题,h2是基于二进制帧的协议,在保留http1.1长连接的前提下,实现了消息的并行处理,请求和响应可以交错甚至可以复用,多个并行请求的开销已经大大降低,我已经不知道还有什么理由继续坚持base64Url的使用了。
