Security News
NIST Misses 2024 Deadline to Clear NVD Backlog
NIST has failed to meet its self-imposed deadline of clearing the NVD's backlog by the end of the fiscal year. Meanwhile, CVE's awaiting analysis have increased by 33% since June.
@nx-js/observer-util
Advanced tools
An NX utility, responsible for powerful data observation with ES6 Proxies.
This library is part of the NX framework.
It provides transparent reactivity without special syntax and with a 100% language observability coverage. It uses ES6 Proxies internally to work seamlessly with a minimal interface. A blog post about the inner working of this library can be found here and a comparison with MobX can be found here.
$ npm install @nx-js/observer-util
import { observable, observe } from '@nx-js/observer-util'
const data = observable({ firstName: 'Bob', lastName: 'Smith' })
observe(() => console.log(`${person.firstName} ${person.lastName}`))
// this logs 'John Smith' to the console
setTimeout(() => person.firstName = 'John')
Any synchronous JavaScript code can be observed - including expando properties, loops, getters/setters, inheritance and ES6 collections. Check out the examples section for more.
No special syntax or setup is required, you will likely use the observable
and observe
functions only.
Observable objects are not modified at all. Seamless proxies are used instead of getters/setters and array hacks. The underlying raw object can be easily retrieved and used when you don't want to trigger observers.
You don't have to explicitly define observable properties. A minimal set of observable properties is automatically maintained based on the observer functions.
Triggered observers run asynchronously, but always before the next repaint in browsers. Your data always reaches a stable and fresh state before repaints.
Duplicates and loops are automatically removed from triggered observers. This ensures that your code won't run twice without a reason.
Creates and returns an observable object.
import { observable } from '@nx-js/observer-util'
const person = observable({ name: 'Ann' })
Returns true if the passed object is an observable, otherwise returns false.
import { observable, isObservable } from '@nx-js/observer-util'
const person = observable()
const isPersonObservable = isObservable(person)
Creates and returns an observer function. An observer automatically reruns when a property of an observable - which is used by the observer - changes.
import { observable, observer } from '@nx-js/observer-util'
const data = observable()
// this logs the data whenever it changes
const logger = observe(() => console.log(data))
Unobserves the passed observer function.
import { observe, unobserve } from '@nx-js/observer-util'
const logger = observer.observe(() => console.log(observable.prop))
unobserve(logger)
Removes the the observer function from the queue of triggered observers. This means that the observer won't run, unless another observable mutation triggers it.
import { observer, unqueue } from '@nx-js/observer-util'
const logger = observe(() => console.log(data))
unqueue(logger)
Immediately runs the observer function. Never run an observer function directly, use this method instead.
import { observe, exec } from '@nx-js/observer-util'
const logger = observe(() => console.log(data))
exec(logger)
Every observable object receives the $raw
virtual property. It can be used to access the underlying non-observable object. Modifying the raw object doesn't trigger observers.
import { observable, observe } from '@nx-js/observer-util'
const person = observable()
const logger = observe(() => console.log(person.age))
// this logs 'Bob'
person.name = 'Bob'
// this won't log anything
person.$raw.name = 'John'
Observer functions run once immediately when they are defined with observe
.
After that, triggered observer functions do not run synchronously. Instead they are saved in a queue and executed in a batch after a small delay. This always happens before the next paint event in the browser.
Observers may trigger other observers by mutating observable objects. In this case the new observers are added to the end of the queue. Infinite loops are automatically resolved and duplicates are removed. This guarantees that observers run only once per batch. A stable and fresh state is always reached when the observer queue empties.
Non mutating operations on observables don't trigger observers. As an example the observable.name = observable.name
set operation won't trigger observer functions.
import { observable, observe } from '@nx-js/observer-util'
const profile = observer.observable()
observe(() => console.log(profile.name))
// outputs 'Bob' to the console
setTimeout(() => profile.name = 'Bob', 100)
import { observable, observe } from '@nx-js/observer-util'
const person = observable({
gender: 'male',
name: 'Potato'
})
observe(() => {
if (person.gender === 'male') {
console.log(`Mr. ${person.name}`)
} else {
console.log(`Ms. ${person.name}`)
}
})
// logs 'Ms. Potato'
setTimeout(() => person.gender = 'female', 100)
import { observable, observe } from '@nx-js/observer-util'
const person = observable({
name: {
first: 'John',
last: 'Smith'
},
age: 22
})
//
observe(() => console.log(`${person.name.first} ${person.name.last}`))
// logs 'Bob Smith'
setTimeout(() => person.name.first = 'Bob', 100)
import { observable, observe } from '@nx-js/observer-util'
const person = observer.observable({
firstName: 'Bob',
lastName: 'Smith',
get name () {
return `${firstName} ${lastName}`
}
})
observe(() => console.log(person.name))
// logs 'Ann Smith'
setTimeout(() => observable.firstName = 'Ann')
import { observable, observe } from '@nx-js/observer-util'
const users = observable([])
observe(() => console.log(users.join(', ')))
// logs 'Bob'
setTimeout(() => users.push('Bob'))
// logs 'Bob, John'
setTimeout(() => users.push('John'))
// logs 'Bob'
setTimeout(() => users.pop())
import { observable, observe } from '@nx-js/observer-util'
const people = observable(new Map())
observe(() => {
for (let [name, age] of people) {
console.log(`${name}, ${age}`)
}
})
// logs 'Bob, 22'
setTimeout(() => people.set('Bob', 22))
// logs 'Bob, 22' and 'John, 35'
setTimeout(() => people.set('John', 35))
import { observable, observe } from '@nx-js/observer-util'
const defaultUser = observable({
name: 'Unknown',
job: 'developer'
})
const user = observable(Object.create(defaultUser))
// logs 'Unknown is a developer'
observe(() => console.log(`${user.name} is a ${user.job}`))
// logs 'Bob is a developer'
setTimeout(() => user.name = 'Bob')
// logs 'Bob is a stylist'
setTimeout(() => user.job = 'stylist', 100)
// logs 'Unknown is a stylist'
setTimeout(() => delete user.name, 200)
This benchmark compares vanilla JS, MobX and nx-observe
in a few scenarios. You can set it up locally with the npm run build-benchmark-mac
or
npm run build-benchmark-ubuntu
command (depending on your OS) and run it
with npm run benchmark
. The result on a MacBook Pro with Node 6.2.0 can be seen below.
The first two tests compare NX and MobX observable creation cost with plain JS object creation.
'New property' tests the cost of adding expando properties to a plain object or an observable without any observer function. MobX requires the special mobx.extendObservable(obj, { prop: 'value' })
syntax instead of obj.prop = 'value'
.
'Get and set operation' tests the cost of get/set operations of a plain object or an observable without any observer function.
'Function creation' tests the cost of vanilla JS function creation versus mobx.autorun(newFn)
and nx.observe(newFn)
.
'Function trigger' tests the cost of intercepting observable property mutations and running the appropriate reactions. The 'no value change' test checks the same thing, in case of observable property mutations without a value change.
'Function cleanup' tests the cost of disposing observer/listener functions with disposeFn()
or signal.unobserve()
.
Do not worry about the large difference between the vanilla and nx-observe / MobX results. The operations tested above are some of the fastest ones in vanilla JS. The overhead would be a lot smaller compared to some commonly used built in objects, like Promises.
This library has the very specific purpose of supporting the NX framework. Features should only be added, if they are used by the framework. Otherwise please fork.
Bug fixes, tests, benchmark corrections and doc updates are always welcome. Tests and linter (standardJS) must pass.
MIT
FAQs
Simple transparent reactivity with 100% language coverage. Made with ES6 Proxies.
The npm package @nx-js/observer-util receives a total of 5,423 weekly downloads. As such, @nx-js/observer-util popularity was classified as popular.
We found that @nx-js/observer-util demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
NIST has failed to meet its self-imposed deadline of clearing the NVD's backlog by the end of the fiscal year. Meanwhile, CVE's awaiting analysis have increased by 33% since June.
Security News
Cloudflare has launched a setup wizard allowing users to easily create and manage a security.txt file for vulnerability disclosure on their websites.
Security News
The Socket Research team breaks down a malicious npm package targeting the legitimate DOMPurify library. It uses obfuscated code to hide that it is exfiltrating browser and crypto wallet data.