How to convert a Javascript Object to a Node Buffer?
Solution 1
A buffer's first argument must be a: String, Buffer, ArrayBuffer, Array, or array-like object.
Taking that information into account, we could implement what you are looking for by creating a buffer from a String. It would look something like the following:
let json = [ 5, false, 55, 'asdf' ];
let buffer = Buffer.from(JSON.stringify(json));
console.log('Buffer: ', buffer); // Buffer: <Buffer 5b 20 35 2c 20 66 61 6c 73 65 2c 20 35 35 2c 20 22 61 73 64 66 22 20 5d>
Then you can bring your JSON back like so:
let converted = JSON.parse(buffer);
console.log('Parsed to json', converted); // Parsed to json [ 5, false, 55, 'asdf' ]
Solution 2
When we are in NodeJS environment we have much better options than, Buffer.from(JSON.stringify(data))
.
Performance wise JSON.stringify + Buffer.from() is ok, but will not work out if the object contains ArrayBuffer, and if done, then very inefficient.
Best way for pure NodeJS based environment
Use "v8 Serialization API" Node JS v8 docs
Its easy to use and built into the Node.js binary.
Its fastest and most space efficient among all the serializers of its kind.
const { serialize, deserialize } = require("v8")
const photo = {
name: "rabbit",
height: 1220,
width: 1440,
tinyThumbnail: jpegFileAsBuffer,
mediumThumbnail: anotherJpegFileAsBuffer,
description: "some string data",
metaData: {
tags: ["rabbit", "animal", "runner"],
type: "image/jpeg"
}
}
const photoSerializedAsBuffer = serialize(photo)
const deserialisedBack = deserialize(photo)
But only issue is, this only works for NodeJS. And C++ if you wish to use "v8" library(I personally not a fan of doing that).
For multi platform support
Use "bson" (MongoDB BSON)
Performance wise its close to v8 parser, but it can be adapted in all platforms where MongoDB is supported, NodeJS, JS in web, Java, C++, rust, ruby, python....
The usage is exactly like v8 serialization API
const { serialize, deserialize } = require("bson")
const photo = {
name: "rabbit",
height: 1220,
width: 1440,
tinyThumbnail: jpegFileAsBuffer,
mediumThumbnail: anotherJpegFileAsBuffer,
description: "some string data",
metaData: {
tags: ["rabbit", "animal", "runner"],
type: "image/jpeg"
}
}
const photoSerializedAsBuffer = serialize(photo)
const deserialisedBack = deserialize(photo)
But it can get difficult when BSON types kick in. But this should not be an issue if the object structure is know, and its unlikely that one may not know the object structure while dealing with cross platform stuff.
However a quick, solution for that in NodeJS is to use bson-buffer
At last
This not a full proof solution, but works great for NodeJS and planning to soon launch this for web JS.
And due to its simple tabular structure we can support this is other platforms too. Feel free to connect if anyone want to collaborate on this.
Related videos on Youtube
Lawrence Douglas
Updated on July 20, 2021Comments
-
Lawrence Douglas almost 3 years
I'm using
Buffer
on my node server andBuffer
on my Javacript client.For the purposes of saving bytes, I'm looking to send my data to the server through websockets as binary as opposed to JSON.
So, if I had the Javascript object of
[ 5, false, 55, "asdf" ]
, I'd like to convert that to the buffer on the client right before sending it. Maybe something like this:object.toBuffer('int16', 'bool', 'int16', 'utf8');
and read it on the server something like this:
var obj = buffer.read('int16', 'bool', 'int16', 'utf8');
I'm looking at current solutions and it looks like I may have to just do a lot of
concat
ing, specifying byte offsets/lengths, converting from ints to booleans, etc.Is there a better way?
Edit: Here's how I think you currently have to do it. I guess my issue is just that it's too verbose and error-prone and I'm looking for a more concise and elegant way to do it, because this operation will be performed in many different places in my code.
// On client for [ 5, false, 55, "test" ] const writeFirst = Buffer.allocUnsafe(2); writeFirst.writeInt16LE(5, 0); const writeSecond = Buffer.allocUnsafe(1); writeSecond.writeUInt8(0); const writeThird = Buffer.allocUnsafe(2); writeThird.writeInt16LE(55, 0); const writeFourth = Buffer.from('test'); const result = Buffer.concat([writeFirst, writeSecond, writeThird, writeFourth]); // On server for reading buffer of [ 5, false, 55, "test" ] const readFirst = result.readInt16LE(0); const readSecond = Boolean(result.readUInt8(2)); const readThird = result.readInt16LE(3); const readFourth = result.toString('utf8', 5);
Edit #2: Was googling around and I think I might want something like protocol buffers. I'm not exactly sure what they are yet or if they apply but it looks like you can specify a schema in a file for all your messages and then serialize your JSON objects to that schema and have it return a buffer, which you can then deserialize using the same schema on the client/other server. I'm going to look in to this some more.
-
dandavis almost 8 yearsyou would have to convert the Buffer to a Blob to send() it on a Socket anyway, and gzip should take care of JSON repetition, which arrays have little of anyway.
-
Lawrence Douglas almost 8 years@dandavis: Why would it have to be a blob? Can't you do
connection.binaryType = "arraybuffer";
? -
dandavis almost 8 yearshmm maybe, i didn't know that was a Socket option, last time i got dirty, only Blobs were working in my project...
-
peteb almost 8 yearsHave you tried
Buffer.from([5, false, 55, 'asdf'], 'binary');
? -
Lawrence Douglas almost 8 years@peteb: I don't think that works with the strings.
-
-
Danibix almost 7 years
new Buffer()
is currently deprecated (even if it's still working in node 8.2). The supported method isBuffer.from(<string>)
-
B''H Bi'ezras -- Boruch Hashem about 5 yearsHi what if my JSON object has 1)a file name (string) and 2)theactual binary data, if I were to JSON.stringify the whole thing, the ArrayBuffer (for me I'm using browser javasript) would be lost in the stringify. Is there a way to convert the JSON to an arraybuffer directly, or add a header to the arraybuffer?
-
Rachael O'James almost 2 yearsBest solution of this task I've ever seen!