代码改变世界

真有必要去除HTML中的空白字符吗?

2009-12-07 17:59 Jeffrey Zhao 阅读(...) 评论(...) 编辑 收藏

刚才有朋友在MSN上问我说,他的页面中有许多空白字符,打开源文件一看发现这代码稀疏得很。他觉得很浪费,他说有什么办法可以去除它们。我问他“你的页面使用GZip压缩了吗?”他说用了,于是我回答说“那么就不用去除空白字符了,连续空白字符压缩得很好,去掉后效果不大的”。这时我又不禁想到早上那篇《博客园首页优化心得》中也有一条是“去除HTML中的空格、空行”,于是我便打算尝试一下,去除空白字符到底有多少效果。

我的实验目标是我博客的前40篇文章的详细页,未压缩前的体积从98K到277K不等,我想也应该算是博客园中比较典型的页面大小吧。我使用这样的测试代码:

static void Main()
{
    var files = Directory.GetFiles(@"d:\pages");
    foreach (var f in files) Compare(File.ReadAllText(f));

    Console.WriteLine("Press enter to exit...");
    Console.ReadLine();
}

private static readonly Regex REGEX_LINE_BREAKS = new Regex(@"\n\s*", RegexOptions.Compiled);
private static readonly Regex REGEX_LINE_SPACE = new Regex(@"\n\s*\r", RegexOptions.Compiled);
private static readonly Regex REGEX_SPACE = new Regex(@"( )+", RegexOptions.Compiled);

private static void Compare(string html)
{
    long original, compressedOriginal;
    GetLength(html, out original, out compressedOriginal);

    long stripped, compressedStripped;
    html = REGEX_LINE_BREAKS.Replace(html, "");
    html = REGEX_LINE_SPACE.Replace(html, "");
    html = REGEX_SPACE.Replace(html, " ");
    GetLength(html, out stripped, out compressedStripped);

    Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}",
        original, compressedOriginal,
        stripped, compressedStripped,
        original - stripped, compressedOriginal - compressedStripped);
}

private static void GetLength(string html, out long original, out long compressed)
{
    var bytes = Encoding.UTF8.GetBytes(html);
    var stream = new MemoryStream();
    var gzipStream = new GZipStream(stream, CompressionMode.Compress);
    gzipStream.Write(bytes, 0, bytes.Length);
    gzipStream.Flush();

    original = bytes.LongLength;
    compressed = stream.Length;
}

在上面这段代码里我使用的是博客园去空白字符的方法,结果如下:

原页面 原页面(压缩) 去空白后 去空白后(压缩) 去空白前后 去空白前后(压缩)
130760 36018 117354 34702 13406 1316
255935 63406 240433 61870 15502 1536
278871 86794 263704 85298 15167 1496
221248 53148 205440 51548 15808 1600
151612 40260 137939 38940 13673 1320
135019 36000 121593 34750 13426 1250
128239 36230 114658 34878 13581 1352
161530 42776 147189 41392 14341 1384
99884 28372 87047 27084 12837 1288
173534 43724 158446 42272 15088 1452
191519 50398 176958 48888 14561 1510
176996 40274 162706 38978 14290 1296
206348 47362 191400 45964 14948 1398
137014 38608 122855 37076 14159 1532
144715 37260 131097 35748 13618 1512
146531 36704 132619 35302 13912 1402
199915 49224 182227 47452 17688 1772
106929 29850 93690 28518 13239 1332
136264 36664 121548 34990 14716 1674
148750 37990 134567 36578 14183 1412
282886 71924 266336 70306 16550 1618
176099 41468 161322 40126 14777 1342
108394 30456 95428 29216 12966 1240
152578 40186 138543 38866 14035 1320
230243 59970 215389 58554 14854 1416
251183 57156 234862 55694 16321 1462
196957 48176 181608 46776 15349 1400
172267 41340 158105 40056 14162 1284
265877 63650 248974 62142 16903 1508
147403 38894 133751 37492 13652 1402
149091 36460 134998 35190 14093 1270
167741 43200 153614 41856 14127 1344
171564 40898 157333 39648 14231 1250
125812 34570 111047 33200 14765 1370
190649 46524 175197 45040 15452 1484
153807 39462 139401 38054 14406 1408
120788 32228 107534 30930 13254 1298
163327 41110 148763 39710 14564 1400
103101 29476 90284 28222 12817 1254
141384 39784 126641 38350 14743 1434

值得关注的是最后两列,从中我们可以发现,虽然去除空白前后可以让页面体积减小十几K,但是经过压缩后其实只相差1-2K了——大约1-2个数据包。这些节省是否值得我们去这么做?再者,博客园的做法是为每个页面的内容使用正则表达式进行替换,那么它所带来开销又是否值得呢?这就要博客园自己进行profiling了……

最后一提,其实去空白字符并非如此简单一件事情。最简单的例子是:您是否遇到某些HTML编辑器或RSS阅读器,它们会让文章中原本工整的代码变成一行?这就是因为它们武断地去除了所有的空白字符,但是忘了有个HTML标记叫做<pre />……