GithubHelp home page GithubHelp logo

Redundant reactions? about observer-util HOT 8 CLOSED

nx-js avatar nx-js commented on August 20, 2024
Redundant reactions?

from observer-util.

Comments (8)

lukeburns avatar lukeburns commented on August 20, 2024 1

Interesting! I'm using node. Wonder why it would be platform specific. Different Proxy implementations?

from observer-util.

solkimicreb avatar solkimicreb commented on August 20, 2024

Hi!

This is normal, but you probably want to do something different.

By default reactions are executed synchronously on observable mutations. This usually results in reactions running a lot of times for complex mutations.

There is a lot going on when you do list.push('World!'). list.length, list[1] and a hidden key for object enumeration changes. console.log(list) uses list.length and the hidden enumeration key to do its work so it updates twice (on each of the two key mutations). This will just get worse with more complex functions. I don't know your use case, but I am pretty sure that you don't want to run reactions synchronously on observable mutations.

You can pass a scheduler to observe. In this case the triggered reaction is not executed synchronously on observable mutations, but passed to the scheduler function instead. Take a look at this example:

import { observe, observable } from '@nx-js/observer-util'
import { Queue, priorities } from '@nx-js/queue-util'

const list = observable(['Hello'])

const scheduler = new Queue(priorities.LOW)
observe(() => console.log(list), { scheduler })

// this passes the reaction to the scheduler
// the scheduler logs ['Hello', 'World!'] once when the browser/Node has some free time
list.push('World!')

Typically a scheduler does two things:

  • It defers the works based on the passed priority.
  • It removes duplicate reactions.

You can use custom schedulers, but I advise you to use the @nx-js/queue-util. You can learn more about schedulers in this docs section, be sure the check all three examples.

I hope this helped 🙂

Edit: By using a bunch of schedulers with different priorities, you can implement something similar to React Fiber

Edit2: A debugger option is under development for observe, which gives you an exact reason for every reaction trigger. It shows you which observable property mutation scheduled the reaction and where does the reaction uses the specific observable property.

from observer-util.

solkimicreb avatar solkimicreb commented on August 20, 2024

@lukeburns can I close this?

from observer-util.

lukeburns avatar lukeburns commented on August 20, 2024

Yep! Thanks for the helpful explanation, and the update on the debug option under development.

from observer-util.

solkimicreb avatar solkimicreb commented on August 20, 2024

I tweaked this behavior a bit in v4.1.0. From now on any atomic operation is guaranteed to schedule a reaction maximum once. By atomic operation I mean a JS operation, which is implemented in none interceptable native code (like property get/set).

Also I added a new experimental debugger. The easiest way of trying it out is this:

let dummy

const person = observable({ name: 'Bob' })
observe(() => dummy = person.name, { debugger: console.log })

person.name = 'Rick'

This logs the context of every single operation that is related to the observed reaction. It will log that person.name is used with a get operation in the reaction and that person.name changed value later. From this stream of data you can deduce why The Observer Util decided to schedule the reaction. The debugger API is designed to be raw. It pushes out a lot of metadata, which meant to be aggregated and filtered by 3rd party libs for larger projects.

from observer-util.

lukeburns avatar lukeburns commented on August 20, 2024

Thanks for your work on this. This change certainly gives me the behavior I originally expected with the code above!

However, I'm receiving a Max call stack size exceeded error with the dummy code you shared above.

Additionally,

const person = observable({ name: 'Bob' })
observe(() => console.log(person))
person.name = 'Rick'

only logs { name: 'Bob' }, when I expect { name: 'Rick' } to also be logged — as in version 4.0.

from observer-util.

solkimicreb avatar solkimicreb commented on August 20, 2024

What platform are you on? Did you get this result in NodeJS or the browser? (For me it seems to be only buggy in NodeJS).

from observer-util.

solkimicreb avatar solkimicreb commented on August 20, 2024

I fixed the first (infinite loop issue) in the 4.1.1 release. Thanks for catching the bug 🙂

The second issue is specific to the NodeJS console.log implementation. Normal for in loops and object enumeration works, but apparently NodeJS console.log is implemented in native code. It is not getting person.name under the hood (you can see this with the now working debugger).

I will see if this can or should be fixed. Is this a big issue for you? I imagine this would only be used for debugging purposes.

Edit: instead of getting each property key, Node gets a shady inspect prop for console.log. I guess Object.prototype has a custom inspect prop in Node which points to some native magic.

from observer-util.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.