【性能优化】前后端使用protobuf高效传递大量数据——前端
Protobuf简单介绍
Google Protocol Buffer(简称 Protobuf)是一种轻便高效的结构化数据存储格式,平台无关、语言无关、可扩展,可用于通讯协议和数据存储等领域。
有几个优点:
- 1.平台无关,语言无关,可扩展;
- 2.提供了友好的动态库,使用简单;
- 3.解析速度快,比对应的XML快约20-100倍;
- 4.序列化数据非常简洁、紧凑,与XML相比,其序列化之后的数据量约为1/3到1/10。
个人感受: 前后端数据传输用json还是protobuf其实对开发来说没啥区别,protobuf最后还是要解析成json才能用。个人觉得比较好的几点是:
- 1.前后端都可以直接在项目中使用protobuf,不用再额外去定义model;
- 2.protobuf可以直接作为前后端数据和接口的文档,大大减少了沟通成本;
- 3.protobuf可以使数据量大大减小,在网络带宽不足的情况下效果很好。
没有使用protobuf之前,后端语言定义的接口和字段,前端是不能直接使用的,前后端沟通往往需要维护一份接口文档,如果后端字段有改动,需要去修改文档并通知前端,有时候文档更新不及时或容易遗漏,沟通成本比较大。
使用protobuf后,protobuf文件由后端统一定义,protobuf直接可以作为文档,前端只需将protobuf文件拷贝进前端项目即可。如果后端字段有改动,只需通知前端更新protobuf文件即可,因为后端是直接使用了protobuf文件,因此protobuf文件一般是不会出现遗漏或错误的。长此以往,团队合作效率提升是明显的。
思路
前端中需要使用 protobuf.js 这个库来处理proto文件。
protobuf.js
提供了几种方式来处理proto。
- 直接解析,如
protobuf.load("awesome.proto", function(err, root) {...})
- 转化为JSON或js后使用,如
protobuf.load("awesome.json", function(err, root) {...})
- 其他
此处使用第一种方式为例:
步骤
1.拿到一份定义好的proto文件。
package awesomepackage; syntax = "proto3"; message AwesomeMessage { string awesome_field = 1; // becomes awesomeField }
2.安装
protobufjs
。
npm i protobufjs
3.编码与解码
import protobuf from "protobufjs"; protobuf.load("awesome.proto", function(err, root) { if (err) throw err; // Obtain a message type var AwesomeMessage = root.lookupType("awesomepackage.AwesomeMessage"); // Exemplary payload var payload = { awesomeField: "AwesomeString" }; // Verify the payload if necessary (i.e. when possibly incomplete or invalid) var errMsg = AwesomeMessage.verify(payload); if (errMsg) throw Error(errMsg); // Create a new message var message = AwesomeMessage.create(payload); // or use .fromObject if conversion is necessary // Encode a message to an Uint8Array (browser) or Buffer (node) // 编码 var buffer = AwesomeMessage.encode(message).finish(); // ... do something with buffer // Decode an Uint8Array (browser) or Buffer (node) to a message // 解码 var message = AwesomeMessage.decode(buffer); // ... do something with message // If the application uses length-delimited buffers, there is also encodeDelimited and decodeDelimited. // Maybe convert the message back to a plain object var object = AwesomeMessage.toObject(message, { longs: String, enums: String, bytes: String, // see ConversionOptions }); });
效果:
4.数据是从后端传来时axios添加响应类型:{ responseType: 'arraybuffer' }
axios.post(url, params, { responseType: 'arraybuffer' })