Protobuf是Google開源的一種可用於結構化數據串行化(序列化)的數據緩存格式,適用於數據存儲以及RPC數據交換格式.php
在前端使用時,會經過自動轉換器將proto文件轉換爲對應的js文件,進行下一步使用。 轉換方式有兩種:前端
proto文件通過轉換後,會生成一個protoFileName.js文件,文件中會包含一系列讀取、設置字段的方法,至關於第一個字段成爲私有字段,同時提供Public的get和set方法,對字段進行處理。這樣的好處是,字段被保護起來,減小出錯,相對安全。java
以下一個proto結構定義,表現的信息git
message Person {
uint32 id = 1;
string first_name = 2;
string last_name = 3;
Email email = 4;
BirthdayMonth birthday_month = 5;
bool active = 6;
}
複製代碼
通過轉換後,(以轉化爲js爲例),成爲一個類的實例,github
至關於緩存
info = new Person()
info.setFisrtName('YOUR FIRST NAME')
info.setLastName('YOUR LAST NAME')
複製代碼
此實例的屬性信息以下, 能夠看到它的原型是jspb.Message, (一個抽象公共類)安全
array: (5) [100, "YOUR FIRST NAME", "YOUR LAST NAME", Array(2), 1]
arrayIndexOffset_: -1
convertedFloatingPointFields_: {}
messageId_: undefined
pivot_:1.7976931348623157e+308
wrappers_: {4: proto.Email}
__proto__: jspb.Message
複製代碼
其中:bash
它的原型方法有哪些呢?數據結構
Object.keys(info.__proto)
// 輸出 ["constructor", "toObject", "serializeBinary", "getId", "setId", "getFirstName", "setFirstName", "getLastName", "setLastName", "getEmail", "setEmail", "clearEmail", "hasEmail", "getBirthdayMonth", "setBirthdayMonth", "getActive", "setActive"]
複製代碼
能夠看到, 除去前兩個方法是Object類型共有,後面的方法都是根據字段自動生成的,其中,若是字段是複合字段,(即message類型),這個字段還會額外增長clearEmail(就是置空)方法。app
代碼示例以下:
proto.Person.prototype.getId = function() {
return jspb.Message.getFieldWithDefault(this, 1, 0);
};
proto.Person.prototype.setId = function(value) {
jspb.Message.setProto3IntField(this, 1, value);
};
proto.Person.prototype.getFirstName = function() {
return jspb.Message.getFieldWithDefault(this, 2, "");
};
proto.Person.prototype.setFirstName = function(value) {
jspb.Message.setProto3StringField(this, 2, value);
};
proto.Person.prototype.getLastName = function() {
return jspb.Message.getFieldWithDefault(this, 3, "");
};
proto.Person.prototype.setLastName = function(value) {
jspb.Message.setProto3StringField(this, 3, value);
};
proto.Person.prototype.getEmail = function() {
return jspb.Message.getWrapperField(this, proto.Email, 4);
};
proto.Person.prototype.setEmail = function(value) {
jspb.Message.setWrapperField(this, 4, value);
};
proto.Person.prototype.clearEmail = function() {
this.setEmail(undefined);
};
proto.Person.prototype.hasEmail = function() {
return jspb.Message.getField(this, 4) != null;
};
proto.Person.prototype.getBirthdayMonth = function() {
return jspb.Message.getFieldWithDefault(this, 5, 0);
};
proto.Person.prototype.setBirthdayMonth = function(value) {
jspb.Message.setProto3EnumField(this, 5, value);
};
proto.Person.prototype.getActive = function() {
return jspb.Message.getFieldWithDefault(this, 6, false);
};
proto.Person.prototype.setActive = function(value) {
jspb.Message.setProto3BooleanField(this, 6, value);
};
複製代碼
每一種數據類型都有對應的賦值方法,最終都會調用同一個方法setFieldIgnoringDefault_
jspb.Message.setProto3IntField = function(msg, fieldNumber, value) {
jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, 0);
};
jspb.Message.setProto3FloatField = function(msg, fieldNumber, value) {
jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, 0.0);
};
jspb.Message.setProto3BooleanField = function(msg, fieldNumber, value) {
jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, false);
};
jspb.Message.setProto3StringField = function(msg, fieldNumber, value) {
jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, "");
};
jspb.Message.setProto3BytesField = function(msg, fieldNumber, value) {
jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, "");
};
jspb.Message.setProto3EnumField = function(msg, fieldNumber, value) {
jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, 0);
};
複製代碼
粗略看過去,方法不少,關鍵參數是其中的1-6的數字,這就是proto定義中的數字,在js實例中,array字段存儲了全部屬性信息,若索引和上述數字是一一對應的,固然,若是字段爲空,在array中會skip.
好比, proto中定義了10個字段,其中只有3,6字段不爲空,則最終數據結構爲
array(empty, emtpy, 3, empty, empty, 6)
複製代碼
這個轉換過程當中,有些細節須要關注。
第一個問題, 如何將proto轉爲js
protobuf 提供的compile, 有相應的php 、js 、Python, java版本, 見github.com/protocolbuf…
第二個問題, 實際的轉化代碼
以js爲例, 用c寫的轉換器,
第三個問題,jspb 從何而來
protobuf/js下binary文件夾及message.js中定義了jspb相關的方法,在轉換過程當中,會自動集成在一塊兒
一些總結:
好處的話很少說,自動轉化,封裝性
還可優化的地方,方法定義太多,致使類似代碼太多冗餘,還能夠再精簡一下,好比get, set方法再進行抽象下,將字段當成參數,不用一必定義,相似php中的__call方法。