0.5.0 • Published 3 years ago

mediary v0.5.0

Weekly downloads
3
License
MIT
Repository
github
Last release
3 years ago

Mediary

Mediary implements structural sharing via proxies in order to provide a transparent virtualization for deep cloning.

Version Travis License

Use Mediary's clone function to get an object representation which, for all intents and purposes, acts like a deeply cloned copy of your original data.

Getting and setting values on this object works natively. You're free to interact as you would with any normal object.

const { clone } = require('mediary');

const foo = {
    a: {
        b: 'b',
        c: 'c'
    }
};

const bar = clone(foo);

bar.a.d = 'd';

console.log(foo); // => { a: { b: 'b', c: 'c' } }

console.log(bar); // => { a: { b: 'b', c: 'c', d: 'd'  } }

The difference between mediary's clone and a naïve deep cloning approach such as JSON.parse(JSON.stringify(foo)) is that under the hood, any changes applied to the "cloned" object are transparently captured in an internal patch layer. The original object's data continues to be referenced for anything which has not been modified.

You can inspect this behavior for yourself using the SymMeta symbol which is exported from the package.

const { clone, SymMeta } = require('mediary');

const foo = {
    a: {
        b: 'b',
        c: 'c'
    }
};

const bar = clone(foo);

bar.a.d = 'd';

console.log(bar.a[SymMeta].patch); // => { d: 'd' }

In this case, an object with d was the only new value added to the patch. The rest of the object representation comes from the original object, foo.

Important Note: The original object will be deeply frozen upon cloning with Mediary. This is to ensure immutability of the new "cloned" object.

const { clone } = require('mediary');

const foo = {
    a: {
        b: 'b',
        c: 'c'
    }
};

const bar = clone(foo);

foo.a = "z";

console.log(foo); // => { a: { b: 'b', c: 'c' } }

It is recommended that you always 'use strict' so that an error is thrown if you attempt to modify the original object.

'use strict';

const { clone } = require('mediary');

const foo = {
    a: {
        b: 'b',
        c: 'c'
    }
};

const bar = clone(foo);

foo.a = "z"; // => TypeError: Cannot assign to read only property 'a' of object '#<Object>'

Benchmarks

See ./bench directory for test setup. Test run is handled by hbu.

Results below are shown ordered by duration—shortest to longest.

Tested on 2.6 GHz Intel Core i7 with 16 GB 2400 MHz DDR4 using Node v11.11.0

Run them for yourself with: npm run benchmark

Incremental Changes

This test simulates the real-world use case of adding small changes over time to a given object. 1000 such changes are made, each to a freshly cloned object. This is similar to how you might use cloning with a library such as redux.

Test LabelDuration (MS)Heap Used (MB)GC Collected Heap (MB)GC Pause Duration (MS)GC Events (major)GC Events (minor)
spread-incremental7.039471.9713.930.9041209
mediary-clone-incremental12.399120.325.830.4434405
mediary-produce-incremental12.477720.375.830.5075105
immer-incremental396.315828.00194.487.09438055

Incremental Changes (in a single pass)

This test simulates the real-world use case of adding lots of small changes to a given object in a single pass. 1000 such changes are made to a single cloned object.

Test LabelDuration (MS)Heap Used (MB)GC Collected Heap (MB)GC Pause Duration (MS)GC Events (major)GC Events (minor)
mediary-clone-incremental-single3.129840.370.000.0000000
mediary-produce-incremental-single3.605660.380.000.0000000
immer-incremental-single5.596531.070.000.0000000

Object Creation

This test forces a memory leak and push 1000 "clones" to an array.

Test data is a large single object (377 KB).

Four clone implementations are tested:

  • immer(data, () = {})
  • mediary.mediary(data)
  • mediary.clone(data)
  • JSON.parse(JSON.stringify(data))
  • deepClone(data) (see ./bench/deepclone-create for implementation)
Test LabelDuration (MS)Heap Used (MB)GC Collected Heap (MB)GC Pause Duration (MS)GC Events (major)GC Events (minor)
immer-leak2.220330.980.000.0000000
mediary-clone-leak10.650972.94-0.521.0521602
stringify-leak1944.64302146.26439.4933.90690345
deepclone-leak2211.25860195.71797.54131.44911665

Property Get

This test reads every leaf on the large test object 1000 times.

Test data is a large single object (377 KB).

Test LabelDuration (MS)Heap Used (MB)GC Collected Heap (MB)GC Pause Duration (MS)GC Events (major)GC Events (minor)
native-read6.784931.040.000.0000000
proxy-read9.470381.000.000.0000000
immer-read1579.616733.23570.5014.192010147
mediary-clone-read1653.338822.4946.592.74192014

Property Set

This test set a new value to every leaf on the large test object 1000 times.

Test data is a large single object (377 KB).

Test LabelDuration (MS)Heap Used (MB)GC Collected Heap (MB)GC Pause Duration (MS)GC Events (major)GC Events (minor)
native-write1435.6218117.450.000.0000000
mediary-clone-write4821.1928215.715698.81272.882161470
immer-write5458.267039.722895.8883.063790208

License

MIT

0.5.0

3 years ago

0.4.1

5 years ago

0.4.0

5 years ago

0.3.1

5 years ago

0.3.0

5 years ago

0.2.11

5 years ago

0.2.10

5 years ago

0.2.9

5 years ago

0.2.8

5 years ago

0.2.7

5 years ago

0.2.6

5 years ago

0.2.5

5 years ago

0.2.4

5 years ago

0.2.3

5 years ago

0.2.2

5 years ago

0.2.1

5 years ago

0.2.0

5 years ago

0.1.1

5 years ago

0.1.0

5 years ago

0.0.11

5 years ago

0.0.10

5 years ago

0.0.9

5 years ago

0.0.8

5 years ago

0.0.7

5 years ago

0.0.6

5 years ago

0.0.5

5 years ago

0.0.4

5 years ago

0.0.3

5 years ago

0.0.2

5 years ago

0.0.1

5 years ago

0.0.0

5 years ago