浏览器中使用Protobuf

· Read in about 1 min · (173 Words)
dev work

Protobuf 作为Google推出的一种二进制结构化数据的格式,可以很好地压缩数据大小,便于传输,同时序列与反序列化的性能很好,所以得到广泛地使用。

但是,前端圈一直以来是以JSON作为数据格式。主要原因如下:

  1. 原生支持

    JSON格式支持已添加到JavaScript标准中,已经是前端的事实以及规范标准。

  2. 易操作性

    JSON格式不仅易于阅读,而且可以直接由JavaScript对象序列化而来,同时可以直接反序列化为JavaScript对象,很便捷。

  3. 性能良好

    JSON格式不管是解析还是序列化的性能都很不错,而且不像XML那样臃肿。

注意 本文并不是为了论证Protobuf比JSON格式优秀,或者说是要在前端弃用JSON。仅仅是为了研究Protobuf在前端使用的可行性,以及如何去使用。

因为前端技术日新月异,很多新技术如WebAssembly, WebRTC,WebSocket, HTTP2等的出现,以及对实时性要求越来越高,使得消息如何传递重新进入话题中心。而Protobuf作为一种优秀的新数据格式标准,很适合消息传递。

关于 Protobuf

对于 Protobuf 是个什么东西,如何编写,网上已经有太多示例了,这里就不再展开描述了。

如果你对 Protobuf 不太熟悉,请参考 Protobuf3 语法指南

编写 proto 文件

使用protobuf作为传输数据格式时,需要先编写相应proto文件。示例(example.proto)如下:

syntax = "proto3";

message User {
    string name = 1;
    int32 age = 2;
    bool male = 3;
}

message Like {
    string sender = 1;
    string post = 2;
    int64 timestamp = 3;
}

这里写了两个数据模型,分别是UserLike模型。 在有了数据模型文件后,需要将其编译成 JavaScript 文件,才能用在前端浏览器中。

编译 proto 文件

进行编译之前,需要先安装相应的 Protobuf 工具。

注意: 这里有两种方式,一种是使用 dcodeIO/Protobuf.js,另一种是使用 Protobuf 官方的 google-protobuf

相对来说,前一种能找到的示例可能更多,后一种很少。甚至连 gRPC 中 Node.js 示例 都提到的是前一种。 但是个人觉得前一种使用方式太过繁琐,甚至有 README 都看不完的感觉。所以这里使用后一种方式。

将 proto 文件编译成代码:

protoc --js_out=import_style=commonjs,binary:. example.proto

经过编译之后,会在当前目录生成一个example_pb.js的文件。这里生成的是 commonjs 风格的代码,还有一种是 Closure 风格的,但是因为对 Closure 不太熟悉,所以略过了…

使用编译后的文件

因为编译成的 commonjs 风格的代码并不能直接在浏览器中使用,所以需要webpack之类的工具将代码融合进去。

const messages = require('./example_pb.js')
// 生成一个 User 对象
let user = new messages.User()
user.setName('Protobuf')
user.setAge(3)
user.setMale(true)
// 将 User 对象序列化成二进制字符串,便于发送到服务端
let bytes = user.serializeBinary()

// 通过 HTTP API 或者 WebSocket 接收到发送过来的数据,反序列化成对象
let like = messages.Like.deserializeBinary(data)
let sender = like.getSender()

将最终的代码文件通过webpack或者browserify等打包工具打包即可在浏览器中引用并正常使用了。

其它

由于 Protobuf 数据是二进制的,所以对其进行处理(特别是接收数据)时,需要注意数据格式的选取。 比如,在使用 WebSocket 的时候,将其类型改为arraybuffer可能会解决某些解析成空对象的错误。

let ws = new WebSocket('ws://localhost:8080/ws')
ws.binaryType = 'arraybuffer'

总体来说,在前端使用 protobuf 并不是太成熟,很可能会遇到一些问题,可以在 Protobuf 的 Github issues 页面搜寻一下相关解决方案或提出你的问题。

引用资料

  1. Protocol Buffers 3 语言指南

Comments