From 3e58f42019064fb8ff7ffbc6c67fe6ace1a2354a Mon Sep 17 00:00:00 2001 From: Marcus Gosselin Date: Thu, 12 Jul 2018 14:56:47 -0400 Subject: [PATCH] initial commit --- package.json | 19 ++++++++++++++++ readme.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ volatile.js | 29 ++++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 package.json create mode 100644 readme.md create mode 100644 volatile.js diff --git a/package.json b/package.json new file mode 100644 index 0000000..93d50b0 --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "volatile", + "version": "7.0.0", + "description": "synchronous volatile thread lock", + "main": "volatile.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/marcus13345/volatile.git" + }, + "author": "Marcus Gosselin", + "license": "ISC", + "bugs": { + "url": "https://github.com/marcus13345/volatile/issues" + }, + "homepage": "https://github.com/marcus13345/volatile#readme" +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..de73b05 --- /dev/null +++ b/readme.md @@ -0,0 +1,62 @@ +# Volatile + +Volatile is a library for serial object mutation powered by es8 async/await. + +By default in javascript, there is only one thread, even with async. so having a simple variable like a counter being accessed from different async threads is not a problem. + +However, when working with something more compliacted, it may be beneficial to be able to lock an object's value while some operations are performed on it, then unlock it afterwards, allowing others to use it. + +## Api + +### Create Volatile Object +- Require the volatile package which returns a class. +- Create an instance of Volatile, giving it the initial value (if any) of your object. +``` javascript +const Volatile = require('volatile'); +let vObject = new Volatile({}); + +// This also works for strings, numbers, symbols, etc +let vString = new Volatile(''); +let vNumber = new Volatile(4); +let vSymbol = new Volatile(Symbol('customSymbol')); +``` + +### Lock the Object and perform Serial Operations +- call lock and pass it a function +- perform operations on the variable +- return back the new value + +The variable is not immutable, however some types, for example number, it would be impossible to mutatue without using an object wrapper. so to make changes, the return value is used. + +The side effect of this, is that if you forget to return, the variable will be set to undefined. + +``` javascript +// despite the timeout, at no time will the variable have both +// 1 and 5 accessible. all operations within a lock are guaranteed to finish +// before moving on to the next lock. +vObject.lock(async function(obj) { + obj.a = 5; + await new Promise(res => setTimeout(_ => res(), 1000)); + obj.b = 5; + return obj; +}); + +vObject.lock(function (obj) { + obj.a = 1; + obj.b = 1; + return obj; +}); +``` + +### toString Behavior + +toString will return the value of invoking the internal variable's toString. If that isnt defined, toString will return `'no toString defined'`. You can create on by locking and adding one. + +``` javascript +vObject.lock(object => { + object.myValue = 5; + object.toString = function() { + return "Custom toString: " + this.myValue; + } +}); +``` \ No newline at end of file diff --git a/volatile.js b/volatile.js new file mode 100644 index 0000000..fd9af7e --- /dev/null +++ b/volatile.js @@ -0,0 +1,29 @@ +mopdule.exports = class Volatile { + constructor(obj) { + this.obj = obj; + } + lock(actionFunction) { + return new Promise(unlock => { + let inst = this; + if (this.queue instanceof Promise) { + this.queue = this.queue.then(async function () { + let ret = actionFunction(inst.obj); + if (ret instanceof Promise) ret = await ret; + inst.obj = ret; + unlock(); + }); + } else { + this.queue = new Promise(async (resolve) => { + let ret = actionFunction(this.obj); + if (ret instanceof Promise) ret = await ret; + this.obj = ret; + unlock(); + resolve(); + }); + } + }); + } + toString() { + return this.obj.toString() || 'no toString defined'; + } +} \ No newline at end of file