前端使用ProtoBuf

什么是ProtoBuf

Protobuf(Protocol Buffers) 是一种由 Google 开发的、语言中立、平台中立、可扩展 的机制,用于 高效地序列化结构化数据。它的核心目的是提供一种比 XML 或 JSON 更小、更快、更简单 的方式来在系统之间(尤其是分布式系统、微服务之间)或用于数据存储时交换数据。

性能对比

同样的数据,压缩10000次,得到以下数据

压缩方式 耗时(压缩10000次耗时) 包大小
Protobuf 9ms 25B
JSON+gZip 483ms 75B

可以看出protobuf相比gzip,耗时更短,压缩率更好,是比较推荐的压缩方式。

ProtoBuf的用法

1. 定义proto文件

首先定义一个proto文件,下面放一个简单的例子

syntax = "proto3";

message Message {
  int32 intValue = 1;
  float floatValue = 2;
  string stringValue = 3;
  
  message Info {
    string name = 1;
  }
  repeated Info arr = 4;
}

上面的proto文件中简单的定义了几个类型,比如int32是整数、float是浮点数(嗯。。。对应前端都是number~~~但是这个是个所有端都能用的类型,所以还是需要区分一下)、string是字符串。里面还定义了一个Info,是为了后面的arr字段是个数组,可以是简单的类型,也可以是自定义的任何类型。

2. 静态编译proto

proto类型也支持动态编译,不过会有一定的耗时,所以我们使用静态编译的方法

安装依赖

npm install protobufjs --save
npm install protobufjs-cli --save-dev

编译命令

"scripts": {
            
  "proto": "pbjs -t static-module -w cmomonjs -o src/proto/message.js proto/message.proto",
},

命令中 -o src/proto/message.js 是静态编译后输出的js文件路径,proto/message.proto是proto源文件的路径

使用方式

encode

// 需要压缩的数据
const data = {
            
  intValue: 1,
  stringValue: "1",
  arr: [{
            name: "1"}, {
            name: "2"}, {
            name: "3"}, {
            name: "4"}],
}
// 执行压缩方法
const buffer = Message.encode(data).finish();

decode

// buffer是上面encode方法返回的Uint8Array
Message.decode(buffer);

兼容性

在定义proto文件的时候我们写了syntax = “proto3” 所以定义的每个字段都是可选的,相当于typescript中每个字段都加了?。如果需要扩展,只需要在定义中增加字段即可,注意=后面的index需要递增。
并且protobuf是所有端都可以使用的一种压缩方式,包括Android、iOS、Windows、Mac、服务端等

代码

<html>
  <head>
    <title>测试protobuf</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  </head>
  <body>
    <script src="../dist/index.js"></script>    
    <script src="pako.js"></script>
    <script>
      const data = {
              
        intValue: 1,
        stringValue: "1",
        arr: [{
              name: "1"}, {
              name: "2"}, {
              name: "3"}, {
              name: "4"}],
      }

      let ts = Date.now();
      for (let i = 0; i < 10000; ++i) {
              
        Message.encode(data).finish();
      }
      console.log("proto time:", Date.now() - ts, "   bytes:", Message.encode(data).finish().byteLength);




      ts = Date.now();
      for (let i = 0; i < 10000; ++i) {
              
        pako.gzip(JSON.stringify(data));
      }
      console.log("gzip time:", Date.now() - ts, "   bytes:", pako.gzip(JSON.stringify(data)).byteLength);
    </script>
  </body>
</html>

其他

如果你也是专注前端多媒体或者对前端多媒体感兴趣,可以搜索微信公众号”前端多媒体”

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容