如何让我的JSON更简洁?

Mar*_*llo 17 string ajax serialization json

我目前正在开发一个Web应用程序,并使用JSON进行ajax请求和响应.我有一个区域,我以一个超过10000个对象的数组的形式向客户端返回一个非常大的数据集.这是示例的一部分(有些简化):

"schedules": [
        {
            "codePractice": 35,
            "codeScheduleObject": 576,
            "codeScheduleObjectType": "",
            "defaultCodeScheduleObject": 12,
            "name": "Dr. 1"
        },
        {
            "codePractice": 35,
            "codeScheduleObject": 169,
            "codeScheduleObjectType": "",
            "defaultCodeScheduleObject": 43,
            "name": "Dr. 2"
        },
        {
            "codePractice": 35,
            "codeScheduleObject": 959,
            "codeScheduleObjectType": "",
            "defaultCodeScheduleObject": 76,
            "name": "Dr. 3"
        }
    ]
Run Code Online (Sandbox Code Playgroud)

可以想象,对于此数组中的大量对象,JSON响应的大小可能非常大.

我的问题是,是否有一个JSON字符串/解析器将"schedules"数组转换为像JSON字符串这样的东西:

"schedules": [
    ["codePractice", "codeScheduleObject", "codeLogin", "codeScheduleObjectType", "defaultCodeScheduleObject","name"],
    [35, 576, "", 12, "Dr. 1"],
    [35, 169, "", 43, "Dr. 2"],
    [35, 959, "", 76, "Dr. 3"],
]
Run Code Online (Sandbox Code Playgroud)

也就是说,在数组的开头会有一个数组,"schedules"它保存这个数组的对象的键,所有其他容器数组都会保存这些值.

如果我愿意,我可以在服务器上进行转换并在客户端上解析它,但我想知道是否有用于解析/字符串化大型JSON的标准库?

我也可以通过一个minifier运行它,但我想保留我目前的密钥,因为它们在应用程序中提供了一些上下文.

我也希望你可以批评我的方法或建议替代方案?

Dav*_*ard 11

HTTP压缩(即gzip或deflate)已经完全正确.重复模式(如JSON密钥)将替换为标记,以便每次传输时只需要发生一次详细模式.

  • 在考虑进行其他优化时,请记住,您的瓶颈可能不会传播.即使是10,000条记录也应该通过电线压缩到不到200k.无论你在客户端使用它们做什么,使用相对较慢的JavaScript,都可能比实际的HTTP传输时间慢得多(并且在JavaScript中必须重构或使用消息的方式增加更多复杂性将增加客户端负担). (2认同)

小智 7

不是答案,而是基于10k条目和一些虚假数据粗略估计"节省":-)这是对我发布的评论的回应.增加的复杂性会使模式化方法值得吗?

"这取决于."

这个C#是LINQPad,可以随时用于测试/修改:

string LongTemplate (int n1, int n2, int n3, string name) {
    return string.Format(@"
            {{
                ""codePractice"": {0},
                ""codeScheduleObject"": {1},
                ""codeScheduleObjectType"": """",
                ""defaultCodeScheduleObject"": {2},
                ""name"": ""Dr. {3}""
            }}," + "\n", n1, n2, n3, name);
}

string ShortTemplate (int n1, int n2, int n3, string name) {
    return string.Format("[{0}, {1}, \"\", {2}, \"Dr. {3}\"],\n",
        n1, n2, n3, name);
}

string MinTemplate (int n1, int n2, int n3, string name) {
    return string.Format("[{0},{1},\"\",{2},\"Dr. {3}\"],",
        n1, n2, n3, name);
}

long GZippedSize (string s) {
    var ms = new MemoryStream();
    using (var gzip = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Compress, true))
    using (var sw = new StreamWriter(gzip)) {
        sw.Write(s);
    }
    return ms.Position;
}

void Main()
{
    var r = new Random();
    var l = new StringBuilder();
    var s = new StringBuilder();
    var m = new StringBuilder();
    for (int i = 0; i < 10000; i++) {
        var n1 = r.Next(10000);
        var n2 = r.Next(10000);
        var n3 = r.Next(10000);

        var name = "bogus" + r.Next(50);
        l.Append(LongTemplate(n1, n2, n3, name));
        s.Append(ShortTemplate(n1, n2, n3, name));
        m.Append(MinTemplate(n1, n2, n3, name));
    }

    var lc = GZippedSize(l.ToString());
    var sc = GZippedSize(s.ToString());
    var mc = GZippedSize(s.ToString());
    Console.WriteLine(string.Format("Long:\tNormal={0}\tGZip={1}\tCompressed={2:P}", l.Length, lc, (float)lc / l.Length));
    Console.WriteLine(string.Format("Short:\tNormal={0}\tGZip={1}\tCompressed={2:P}", s.Length, sc, (float)sc / s.Length));
    Console.WriteLine(string.Format("Min:\tNormal={0}\tGZip={1}\tCompressed={2:P}", m.Length, mc, (float)mc / m.Length));
    Console.WriteLine(string.Format("Short/Long\tRegular={0:P}\tGZip={1:P}",
        (float)s.Length / l.Length, (float)sc / lc));
    Console.WriteLine(string.Format("Min/Long\tRegular={0:P}\tGZip={1:P}",
        (float)m.Length / l.Length, (float)mc / lc));
}
Run Code Online (Sandbox Code Playgroud)

我的结果:

Long:  Normal=1754614  GZip=197053  Compressed=11.23 %
Short:  Normal=384614  GZip=128252  Compressed=33.35 %
Min:  Normal=334614  GZip=128252  Compressed=38.33 %
Short/Long  Regular=21.92 %  GZip=65.09 %
Min/Long  Regular=19.07 %  GZip=65.09 %

结论:

  • 最大的节省是使用GZIP(比使用schema'ize更好).
  • GZIP + schema'ized将是最小的整体.
  • 使用GZIP,没有必要使用普通的JavaScript最小化器(在这种情况下).
  • 使用GZIP(例如DEFLATE); 它在重复的结构化文本上表现很好(正常情况下压缩率为900%!).

快乐的编码.


Cᴏʀ*_*ᴏʀʏ 6

这篇文章几乎完成了你要做的事情:

http://stevehanov.ca/blog/index.php?id=104

乍一看,看起来您的示例将在算法的第一步之后压缩到以下内容,这将在后续步骤中实际执行更多工作):

{
    "templates": [ 
        ["codePractice", "codeScheduleObject", "codeScheduleObjectType", "defaultCodeScheduleObject", "name"] 
    ],
    "values": [ 
        { "type": 1, "values": [ 35, 576, "", 12, "Dr. 1" ] },
        { "type": 1, "values": [ 35, 169, "", 43, "Dr. 2" ] },
        { "type": 1, "values": [ 35, 959, "", 76, "Dr. 3" ] }
    ]
}
Run Code Online (Sandbox Code Playgroud)

您可以开始看到算法的好处.这是通过压缩器运行后的最终输出:

{
    "f" : "cjson",
    "t" : [
              [0,"schedules"],
              [0,"codePractice","codeScheduleObject","codeScheduleObjectType","defaultCodeScheduleObject","name"]
          ],
    "v" : {
        "" : [ 1, [
                { "" : [2, 35, 576, "", 12, "Dr. 1"] },
                { "" : [2, 35, 169, "", 43, "Dr. 2"] },
                { "" : [2, 35, 959, "", 76, "Dr. 3"] }
            ]
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你有几千条记录,显然可以看到改进.输出仍然是可读的,但我认为其他人也是对的:一个好的压缩算法将删除无论如何重复的文本块...