Open hansihe opened 3 years ago
@hansihe Have you tried using JSON Patch? Perhaps this could help with the serialization step, and it is already implemented in most languages.
Here is the implementation on Elixir:
https://hexdocs.pm/jsonpatch/readme.html
Dart:
https://pub.dev/packages/json_patch
JS:
https://www.npmjs.com/package/fast-json-patch https://www.npmjs.com/package/rfc6902
To reduce the Payload you could do some compression like:
On elixir side:
@json_patch_remove 0
@json_patch_add 1
@json_patch_replace 2
@json_patch_test 3
@json_patch_move 4
@json_patch_copy 5
defp compress_json_patch(patch) when is_list(patch) do
Enum.flat_map(patch, &compress_json_patch/1)
end
defp compress_json_patch(%{op: "add", path: path, value: value}) do
[@json_patch_add, path, value]
end
defp compress_json_patch(%{op: "replace", path: path, value: value}) do
[@json_patch_replace, path, value]
end
defp compress_json_patch(%{op: "test", path: path, value: value}) do
[@json_patch_test, path, value]
end
defp compress_json_patch(%{op: "move", path: path, from: from}) do
[@json_patch_move, path, from]
end
defp compress_json_patch(%{op: "copy", path: path, from: from}) do
[@json_patch_copy, path, from]
end
defp compress_json_patch(%{op: "remove", path: path}) do
[@json_patch_remove, path]
end
On the client side:
const OPERATIONS = new Map([
[0, "remove"],
[1, "add"],
[2, "replace"],
[3, "test"],
[4, "move"],
[5, "copy"],
]);
function decompress(diff) {
const decoded = [];
for (let i = 0; i < diff.length; i++) {
const op = diff[i];
const patch = {
op: OPERATIONS.get(op),
path: diff[++i],
};
if (["add", "replace", "test"].includes(patch.op)) {
patch.value = diff[++i];
} else if (patch.op !== "remove") {
patch.from = diff[++i];
}
decoded.push(patch);
}
return decoded;
}
Yep, I looked at using jsonpatch initially. Unfortunately it doesn't mesh very well with the fragment/template approach this library uses to minimize the data sent over the wire.
While jsonpatch having implementations in a lot of languages already is nice, I would argue:
If we know the set of variables captured by a
keyed
, we can be smarter about when it is reevaluated.As an example:
If we know that the
keyed post.id
block only uses state from withinpost
, and we knowpost
has not changed since the last render, we can omit rendering that subtree entirely.This is a simple example, so omitting rendering the subtree would not give us much here, but when scaled to deeper and more complicated data structures, being able to omit rendering subtrees like this could be a major advantage.