阅读 150

flatBuffer在前端的实际应用

简介

FlatBuffers是针对C ++,C#,C,Go,Java,JavaScript,Lobster,Lua,TypeScript,PHP,Python和Rust的高效跨平台序列化库。它最初是由Google创建的,用于游戏开发和其他对性能至关重要的应用程序。

github地址 github.com/google/flat…

为什么不用JSON

Json是当今全服务平台的轻量级数据传输格式,Json量级轻,并且可读性强,使用友好却不过时,Json是语言独立的数据格式,但Json转换的时候却耗费较多的时间和内存。所以在游戏开发和其他对性能至关重要的应用程序中JSON是无法支撑的。

使用

1.生成flatc

官方文档介绍:google.github.io/flatbuffers… 我是没怎么看懂,我直接找的github上的版本管理里的包,下载使用即可。

2.编写schema文件

schema 接口定义语言(IDL)的语法与C系列语言和其他IDL语言的语法相似。如何编写请详细查看官方文档。

这块是数据传输的关键部分,定义的数据结构展示在这里,所以这里的设计好坏在以后的开发中至关重要。

以下是我的一个简单示例

namespace cn.pinming.bimplatform.component.flatbuffer;

table HandleList{
     proGuid:string;
     projectId:string;
     mainMode:byte;
     kindId:int;
     pricingId:string;
     pricingname:string;
     itemFeature:string;
     floorId:int;
     handles:[Handle];
}

table Handle {
    handle:string;
    floor:int;
}

root_type  HandleList;
复制代码

3.使用flatc编译schema文件

官方文档介绍了flatc使用语法,并可以编译成各种编程语言所需的文件。

以js为例

flatc -o ./ -s ./文件名.fbs
复制代码

使用方法:找到flatc.ext文件夹位置,在文件夹中拷入要编译的文件,用cmd打开此文件夹,输入命令编译,会生成_generated的文件。

4.根据schema文件生成/解析数据

js使用需要官方的解析函数库,可以在github代码库可找到flatbuffers/js。

4.1 以下是生成flatBuffer数据的列子

根据schema文件封装的构造函数,传进所需的数据构造出flatBuffer数据。

// schema文件结构
namespace cn.pinming.bimplatform.component.flatbuffer;

table HandleList{
     proGuid:string;
     projectId:string;
     mainMode:byte;
     kindId:int;
     pricingId:string;
     pricingname:string;
     itemFeature:string;
     floorId:int;
     handles:[Handle];
}

table Handle {
    handle:string;
    floor:int;
}

root_type  HandleList;
复制代码
import { flatbuffers } from "@/flatBuf/flatbuffers"
import { cn } from '@/flatBuf/Handle_generated'

const handleNameSpace = cn.pinming.bimplatform.component.flatbuffer

function HandleInterface () {
  this.type = 'handleInterface'
}

HandleInterface.prototype = {
  constructor: HandleInterface,

  // 传进所需的数据构造出对应的flatBuffer数据
  setFlatBuffer: function (projectData, handlesArray) {
    // 创建 `FlatBufferBuilder` 实例, 用它来开始创建 FlatBuffers ,初始化大小 1024
    // buffer 的大小会根据需要自动增长,所以不必担心空间不够
    let builder = new flatbuffers.Builder(1024)

    // Create the `HandleArray`
    let HandleArray = []
    for (let i = 0; i < handlesArray.length; i++) {
      let handleString = builder.createString(handlesArray[i].handle)
      handleNameSpace.Handle.startHandle(builder)
      handleNameSpace.Handle.addHandle(builder, handleString)
      handleNameSpace.Handle.addFloor(builder, handlesArray[i].floor)
      let HandleArrayOffset = handleNameSpace.Handle.endHandle(builder)
      HandleArray.push(HandleArrayOffset)
    }

    // Create the `HandleList`
    let proGuidString = builder.createString(projectData.proGuid) // string类型的不可直接取值,必须createString,而且查看源码可知createString里调用了start和end,所以不能嵌套在下面的startHandleList里,不然会有两个start。
    let projectIdString = builder.createString(projectData.projectId)
    let pricingIdString = builder.createString(projectData.pricingId)
    let pricingNameString = builder.createString(projectData.pricingName)
    let itemFeatureString = builder.createString(projectData.itemFeature)
    let HandleArrayVec = handleNameSpace.HandleList.createHandlesVector(builder, HandleArray) // 对象需要create
    handleNameSpace.HandleList.startHandleList(builder)
    handleNameSpace.HandleList.addProGuid(builder, proGuidString)
    handleNameSpace.HandleList.addProjectId(builder, projectIdString)
    handleNameSpace.HandleList.addMainMode(builder, projectData.mainMode) // byte类型可以直接取值
    handleNameSpace.HandleList.addKindId(builder, projectData.kindId) // int类型可以直接取值
    handleNameSpace.HandleList.addPricingId(builder, pricingIdString)
    handleNameSpace.HandleList.addPricingName(builder, pricingNameString)
    handleNameSpace.HandleList.addItemFeature(builder, itemFeatureString)
    handleNameSpace.HandleList.addHandles(builder, HandleArrayVec)
    let HandleList = handleNameSpace.HandleList.endHandleList(builder) // 调用end生成HandleList对象

    builder.finish(HandleList) // Call `finish()` to instruct the builder that this monster is complete.
    return builder.asUint8Array() // Of type `Uint8Array`. This must be called after `finish()`
  },
}

export default HandleInterface
复制代码

4.2 以下是解析flatBuffer数据的列子

namespace cn.pinming.bimplatform.component.flatbuffer;

table CompList{
    children:[Component];
}

table Component{
    name:string;
    unit:string;
    quantity:double;
}
root_type CompList;
复制代码
import { flatbuffers } from "@/flatBuf/flatbuffers"
import { cn } from '@/flatBuf/ComponentQty_generated'

const ComponentQtyNameSpace = cn.pinming.bimplatform.component.flatbuffer

function ComponentQtyInterface () {
  this.type = 'ComponentQtyInterface'
}

ComponentQtyInterface.prototype = {
  constructor: ComponentQtyInterface,

    // 解析头文件
  createHeadDataFile: function (bytes) {
    let data = new Uint8Array(bytes) // 根据传输过来的数据new出Uint8Array对象
    let buf = new flatbuffers.ByteBuffer(data) // 根据Uint8Array生成ByteBuffer
    let head = ComponentQtyNameSpace.CompList.getRootAsCompList(buf) // Get an accessor to the root object inside the buffer.
    return head
  },

  getCompList: function (headDataFile) {
    let children = []
    for (let i = 0; i < headDataFile.childrenLength(); i++) {
      children.push(this.getComponent(headDataFile.children(i)))
    }

    return {
      children: children
    }
  },

  getComponent: function (data) {
    let obj = {}

    obj.name = data.name()
    obj.unit = data.unit()
    obj.quantity = data.quantity()

    return obj
  }
}

export default ComponentQtyInterface
复制代码

ajax请求中要告知传输的数据类型

// 不同的ajax库中有不同的写法,最主要的是responseType: 'arrayBuffer',自己查询此用法
export async function entityQtyDetailByHandles(data) {
  return request(`${bimServer}/front/analysis/entityQtyDetailByHandles`, {
    method: 'POST',
    responseType: 'arrayBuffer',
    data
  });
}
复制代码
entityQtyDetailByHandles(requestData).then((itemData: any) => {
  const head = entityQtyDetailInterface.createHeadDataFile(itemData)
  const etqDetail = entityQtyDetailInterface.getEntityQtyDetail(head)
})
复制代码

总结

看了实际应用后可以发现flatBuffer使用起来还是有点麻烦的,不像JSON结构那样简洁明了,一目了然。所以不建议所有接口使用flatBuffer,只对那种数据结构超大,传输速度要求极高的场景下才使用。还是JSON结构友好,也便于看数据返回字段就能发现问题所在,而用了flatBuffer就必须打开本地开发环境调试代码查看数据内容(因为传输的是二进制的数据格式,不经过解析是看不懂的)。

关注下面的标签,发现更多相似文章
评论