Comparing version 1.0.3 to 1.1.0
83
index.js
@@ -1,11 +0,18 @@ | ||
module.exports = function (filter) { | ||
var value = null, listeners = [], oncers = [] | ||
module.exports = function Obz(filter) { | ||
let value = null | ||
const listeners = [] | ||
let oncers = [] | ||
function trigger (_value) { | ||
value = _value | ||
var length = listeners.length | ||
for (var i = 0; i < length && value === _value; i++) { | ||
function trigger(nextValue) { | ||
value = nextValue | ||
let length = listeners.length | ||
for (let i = 0; i < length && value === nextValue; i++) { | ||
const listener = listeners[i] | ||
listener(value) | ||
if (listeners.length !== length) { // remove | ||
if (listener(value) === false) { | ||
listeners.splice(i, 1) | ||
i-- | ||
length-- | ||
} | ||
if (listeners.length !== length) { | ||
// something was removed | ||
length = listeners.length | ||
@@ -18,38 +25,44 @@ if (listener !== listeners[i]) { | ||
} | ||
// decrement from length, incase a !immediately | ||
// decrement from length, in case an immediately | ||
// listener is added during a trigger | ||
var l = oncers.length | ||
var _oncers = oncers | ||
let oncersLen = oncers.length | ||
const oldOncers = oncers | ||
oncers = [] | ||
while (l-- && _value === value) { | ||
_oncers.shift()(value) | ||
while (oncersLen-- && nextValue === value) { | ||
oldOncers.shift()(value) | ||
} | ||
} | ||
function many (ready, immediately) { | ||
var i = listeners.push(ready) - 1 | ||
if (value !== null && immediately !== false) ready(value) | ||
return function () { //manually remove... | ||
//fast path, will happen if an earlier listener has not been removed. | ||
if (listeners[i] !== ready) | ||
i = listeners.indexOf(ready) | ||
listeners.splice(i, 1) | ||
function obz(listener, immediately) { | ||
let i = listeners.push(listener) - 1 | ||
if (value !== null && immediately !== false) { | ||
if (listener(value) === false) { | ||
remove() | ||
return function noop() {} | ||
} | ||
} | ||
function remove() { | ||
// manually remove... | ||
// fast path, will happen if an earlier listener has not been removed. | ||
if (listeners[i] !== listener) i = listeners.indexOf(listener) | ||
if (i >= 0) listeners.splice(i, 1) | ||
} | ||
return remove | ||
} | ||
many.set = function (_value) { | ||
if (filter ? filter(value, _value) : true) trigger(many.value = _value) | ||
return many | ||
obz.set = function set(nextValue) { | ||
if (filter ? filter(value, nextValue) : true) { | ||
trigger((obz.value = nextValue)) | ||
} | ||
return obz | ||
} | ||
many.once = function (once, immediately) { | ||
if(value !== null && immediately !== false) { | ||
once(value) | ||
return function () {} | ||
} | ||
else { | ||
var i = oncers.push(once) - 1 | ||
return function () { | ||
if(oncers[i] !== once) | ||
i = oncers.indexOf(once) | ||
obz.once = function once(oncer, immediately) { | ||
if (value !== null && immediately !== false) { | ||
oncer(value) | ||
return function noop() {} | ||
} else { | ||
const i = oncers.push(oncer) - 1 | ||
return function remove() { | ||
if (oncers[i] !== oncer) i = oncers.indexOf(oncer) | ||
} | ||
@@ -59,3 +72,3 @@ } | ||
return many | ||
return obz | ||
} |
{ | ||
"name": "obz", | ||
"description": "simple and lightweight observer", | ||
"version": "1.0.3", | ||
"version": "1.1.0", | ||
"homepage": "https://github.com/ssbc/obz", | ||
@@ -14,7 +14,8 @@ "repository": { | ||
}, | ||
"author": "'Dominic Tarr' <dominic.tarr@gmail.com> (dominictarr.com)", | ||
"license": "MIT", | ||
"scripts": { | ||
"test": "set -e; for t in test/*.js; do node $t; done" | ||
}, | ||
"author": "'Dominic Tarr' <dominic.tarr@gmail.com> (dominictarr.com)", | ||
"license": "MIT" | ||
} | ||
"readme": "# obz\n\nA fork of https://github.com/dominictarr/obv\n\nRepresents a value changing in time.\n\nSometimes you have a sequence of values over time,\nusually we use streams for this. However, in some cases,\nthe latest value, or the next value matters more\nthan the entire history of values.\n\nFor example, if you are drawing the mouse pointer,\nyou just need the current position, not the historical positions.\n\nAn observable is a simple way to represent these instantaniously changing values.\n\n## Obv() => observable\n\nreturns an observable instance.\n\n## observable(listener=function, immediate=boolean) => remove\n\nregister `listener` with the observable. `immediate` is true by default.\n`listener` is called with the current value (if one has been set), set to false to disable.\n\nA function `remove` is returned, calling this function deregisters the listener.\n\nAnother way of deregistering the listener is by returning `false` from inside the\nlistener function.\n\n## observable.set(value=any)\n\nset the current value of this observable. Any registered listeners will be called.\n\n## observable.once(listener=function, immediate=boolean) => remove\n\nLike the above call to `observable()` except the listener will only be triggered _once_.\n\nThis is useful for representing variables which must be set after an async operation\n(say, initializing a database connection), but if the value is initalized\nyou can act on it immediately.\n\nIf you call `observable.once(listener, false)` that triggers at the _next_\ntime the value is set, which so far I have used to create live streams.\n\n## observable.value\n\nThe current value of the observable is provided as a property.\nI recommend not using null as a observable value in your program,\nbecause it makes testing the current value awkward.\n\n## License\n\nMIT\n\n" | ||
} |
@@ -28,2 +28,5 @@ # obz | ||
Another way of deregistering the listener is by returning `false` from inside the | ||
listener function. | ||
## observable.set(value=any) | ||
@@ -30,0 +33,0 @@ |
@@ -79,2 +79,59 @@ var tape = require('tape') | ||
tape('remove itself, simple', function (t) { | ||
var o = observable() | ||
t.plan(1) | ||
o(function (val) { | ||
t.equals(val, 10) | ||
return false | ||
}) | ||
o.set(10) | ||
o.set(20) | ||
t.end() | ||
}) | ||
tape('remove itself, complex', function (t) { | ||
var o = observable() | ||
t.plan(5) | ||
var remove = o(function (val) { | ||
t.equals(val, 10) | ||
return false | ||
}) | ||
const expected = [10, 20] | ||
// 2nd listener remains functional after 1st listener is removed | ||
o(function (val) { | ||
t.true(expected.length > 0) | ||
t.equals(val, expected.shift()) | ||
}) | ||
o.set(10) | ||
remove() // should do nothing | ||
o.set(20) | ||
t.end() | ||
}) | ||
tape('remove itself (immediately)', function (t) { | ||
var o = observable() | ||
o.set(10) | ||
o(function (val) { | ||
t.equals(val, 10) | ||
return false | ||
}, true) | ||
o.set(20) | ||
t.end() | ||
}) | ||
tape('flatten recursion', function (t) { | ||
@@ -81,0 +138,0 @@ var o = observable() |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
13410
10
315
56