causality

所属分类:代理服务器
开发工具:JavaScript
文件大小:0KB
下载次数:0
上传日期:2023-02-27 17:26:23
上 传 者sh-1993
说明:  基于Javascript代理(ES6)的 React编程库
(A library for reactive programming based on Javascript proxies (ES6))

文件列表:
.dir-locals.el (91, 2023-08-09)
.eslintrc.js (352, 2023-08-09)
bower.json (512, 2023-08-09)
causality.js (57940, 2023-08-09)
docs/ (0, 2023-08-09)
docs/causality.svg (6698, 2023-08-09)
docs/logotype.png (11590, 2023-08-09)
docs/paradigms.txt (109, 2023-08-09)
docs/performance.png (6485, 2023-08-09)
docs/reCached.png (54562, 2023-08-09)
docs/todo.txt (14, 2023-08-09)
experiments/ (0, 2023-08-09)
experiments/100k_observers.js (1680, 2023-08-09)
experiments/500k_observers_and_sources.js (1598, 2023-08-09)
experiments/array-splices-performance.js (5727, 2023-08-09)
experiments/async/ (0, 2023-08-09)
experiments/async/expected.js (706, 2023-08-09)
experiments/async/setup.js (4994, 2023-08-09)
experiments/async/test.js (1829, 2023-08-09)
experiments/const.js (651, 2023-08-09)
experiments/performance.js (4274, 2023-08-09)
lib/ (0, 2023-08-09)
lib/caching.js (3884, 2023-08-09)
lib/defaultDependencyInterface.js (6598, 2023-08-09)
lib/objectlog.js (9890, 2023-08-09)
lib/utility.js (4985, 2023-08-09)
package-lock.json (88469, 2023-08-09)
package.json (749, 2023-08-09)
test/ (0, 2023-08-09)
test/array-splices.js (1874, 2023-08-09)
test/array.js (3715, 2023-08-09)
test/bower.js (407, 2023-08-09)
test/cache.js (1102, 2023-08-09)
test/classes.js (1023, 2023-08-09)
test/eslint.js (759, 2023-08-09)
test/hobby_list.js (992, 2023-08-09)
test/meta_repeaters.js (3853, 2023-08-09)
test/observe.js (1898, 2023-08-09)
... ...

# Causality ![Alt text](https://github.com/docs/logotype.png?raw=true "Causality Logotype") Simple, scalable state management and reactive programming, using ES6 proxies. # Installation Installation: npm install causalityjs --save # Getting Started It is possible to create several instances of causality, called worlds, each with its separate config and dependencies. As the name implies, you typically just create one single causality world for your app to use. But you can sometimes benefit from created several isolated worlds where causality isolates observation and event propagation within each world. import getWorld from "causality"; let myWorld = getWorld({name: "myWorld", ...moreOptions}); // Create an instance with possibility to configure it. let { observable, repeat } = myWorld; Calling getWorld multiple times with the same unique name given in the configuration, will return the same world object. Only the options given the first time will be considered. For consequtive calls with the same world name, the options will be ignored. # Quick Example This is just to show a simple example of what causality is all about, using the simple repeat primitive. import getWorld from "causality"; let { observable, repeat } = getWorld(); let x = observable({propA: 11}); let y = observable({propB: 11, propC: 100}); let z; repeat(function(){ z = x.propA + y.propB; // Sets up a reactive setting of variable z }); // z is now 22 y.propB = 2; // Setting of propB will cause reevaluation of z // z is now 13 x.propA = 2; // z is now 4 However, there are a lot more interesting features to try out. # Features ## observable With observable you simply create a causality object. The observable function takes any other Javascript object as input. Example usage: observable({a: 1, b: 2, c: 3}); observable([1, 2, 3]); observable(new MyClass()); A causality object is an object that can be observed by causality. This means that changes in causality objects will be detected automatically by the causality framework. While it is possible to mix the use of causality object and plain Javascript object, it is not recommended to do so, as changes in plain Javascript objects will go undetected by causality. In every other aspect, a causality object behaves just as an ordinary Javascript object would. So you could for example write: var x = observable({a: 1, b: 2}); var y = x.a + b.2; // should result in 3! var l = observable([]); l.push("item1"); l.push("item2"); l.pop(); console.log(l); // should print out ["item1"]; If you find it too cumbersome to write "observable" upon every object creation, you can create an alias "o": o({a: 1, b: 2}); To access the inner workings of a causality object, you can access it by the causality property. For example write object.causality.id to get a system wide unique id for that particular object. ## repeat Repeat is typically used to enforce some certain data constraint. Such as reactive validation of a form, or calculation of some. In its basic form, it is simply a function that is reevaluated every time any of the data it read changes. For example: repeat(function() { x.value = y.value + z.value; }); This will cause x.value to be assigned to y.value + z.value any time either y.value or z.value changes. The good part is that you can write any kind of code inside the function. There can be loops, function calls, recursive functions. Anything. And no matter what code is there, causality will always keep track of what data has been read by the repeater function at any given moment. It will however not detect changes in local variables, so for example if local or global variable y is assigned in this example, there will be no reevaluation of x.value. In practice however, this is in general not a limitation as application code typically reacts to changes to a specific model, rather than changes in local variables. ## Using repeat with rebuilding keys repeat is equipped with some special features when it comes to creating data structures. Assume that you have an algorithm that constructs a data structure. For example a balanced index structure of some sort. However, when the input data is changed and the algorithm needs to repeat once more, you do not want a completely new output data structure. Instead, you want to execute the algorithm once more, and at the end of it, compare the difference to the result of the last run, and update the previous result in a minimal way. This is something that is supported with causality! React users might notice that this is actually a generalization of how React works with the synthetic dom. But instead of being limited to just dom structures, causality can do this trick for any data structure! For example: repeat(() => { for(let input of inputArray) { addToIndex(observable({value: input.value},"buildId" + input.id)) } }) Note that the only difference is that we added a unique build id for each created object in the data structure. This way causality will know what previously created object correspond to the objects created at each repetition. ## Non recorded action with repeat A repeater can mix cause and effect, and there are some preventive measures in place to prevent a repeater from activating itself. So, in many cases it is safe to use a repeater with a single action (comparable to autorun in MobX). However, there could be situations where you would like to distinguish more between cause and effect. To do that, a second argument for the repeater is an action that is not recorded. repeater([description for debug], recordedAction, nonRecordedAction, options) The options object contains further configurations for the non-recorded action. Namley debounce and fireImmediatley. The return value of the recorded action will be sent as an argument to the nonRecorded action, similar to how reaction works in MobX. ## invalidateOnChange There is a famous quote from programmer Jeff Atwood (author of blog Coding Horrors): *There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.* Well, at least cache invalidation just got much more simple thanks to invalidateOnChange. While you could use a repeat to invalidate a cache, invalidateOnChange is a more basic primitive that is optimized for this specific purpose (it is used by repeat internally). For example, if a cache is filled up using lazy evaluation, it is convenient to just clear the cache without any direct reevaluation. Here is an example: let x = observable({value: null, isValid: false}); getX() { if (!x.isValid) { invalidateOnChange( function() { x.value = y.value + z.value; x.isValid = true; }, function() { x.isValid = false; } ); } return x.value; } In this case, if y.value is changed for instance, it will only mean that the second function is run, setting x.isValid to false. invalidateOnChange is in particularly useful when integrating causality with other frameworks. For example, rendering code could be run using invalidateOnChange, and the second function could simply invalidate a certain view-component. ## withoutRecording and withoutReactions When working with causality it could be useful to sometimes break the rules. Reading data without creating a dependency could for example be useful for debug printouts. In the following code, the debug printout itself would create a false dependency on `z.value` if it wasnt for the withoutRecording clause. let x = null let y = observable({ value: false }); let z = observable({ value: 10}); repeat(function() { withoutRecording(function() { console.log("Repeating with these values:"); console.log(y.value); console.log(z.value); }) if (y.value) { x = z.value; } else { x = 42; } } // No one is going to notice! withoutReactions(function() { y.value = true; }); There are probably less use cases for being able to change data without triggering any reactions, using withoutReactions, it is available nevertheless. ## Emiting Events Somtimes you just need to observe objects, and record events. For this purpose you can set an onEventGlobal callback in the causality configuration. This callback can then monitor any change that happens in the world from a birds eye perspective. Activating sendEventsToObjects will also cause causality to try to send events directly to your observable objects. If your objects implement the following callbacks, causality will then try to call them. - onChange (or you should just reactivley listen to changes, using repeat etc.) - onEstablish - onDispose onChange will receive a message, containing information about any change that happened to the object. The onEstablish and onDispose events will be sent specifically when doing data structure rebuilding. They correspond to the React concepts of componentDidMount and componentWillUnmount but for a generalized data structure re building framework. ## causality.forwardTo The re building mechanism internally uses a forwarding mechanism that can be used directly. To use it, simply type myObject.causality.forwardTo = otherObject. This will cause myObject have the identity of myObject, but the state of otherObject. Quite useful for some very special scenarios. Note that the forwarding disregards the meta data of the object that is reached by myObject.causality. As a consequence of this, object.causality.id cannot be relied upon when forwarding is used, such as in a rebuilding scenario. Also, forwarding takes place before any onReadGlobal and onWriteGlobal event can be fired, those events will be fired, but for the object that the object was forwarding to. ## transaction It is possible to do many changes at once, before causality has a chance to responde to any of the changes. This can be done by the use of "transaction". Here is an example: transaction(function() { x.a = 12; x.b = 30; }) Warning: A transaction should typically only write data, as reading data inside a transaction might result in reading non-updated data since all repeaters are frozen inside the transaction. # Release Notes for 3.0 ## Removed features Since version 2.0 a few features were removed, as they seemed too esoteric to be practically used. For example cached, reCached, withoutSideEffects etc. if you miss any of these features, please let us know. The idea is that using rebuilding keys in a standard repeat should replace reCached, and that cached functions can be implemented fairly easily using invalidateOnChange. ## Migration The 3.0 version uses a getWorld function that can create multiple instances of causality. ```js import getWorld from "/vendor/causalityjs/causality.js"; const myCausalityWorld = getWorld({name: "myCausalityWorld", ...moreOptions}); const { repeat, invalidateOnChange, observable } = myCausalityWorld; ``` You can name a configuration with the "name" property. Doing so makes it possible to retrieve the same instance from another call to the factory function. A named configuration is created the first time by using the configuration, on successive calls by using the same name, configuration settings will be ignored and you will just be given the instance created the first time that name was used. `Causality.create` has been renamed `Causality.observable`. However, create still exists as an alias. `Causality.independently` is no longer needed for repeaters created inside other repeaters, since now, the default behaviour is that sub-repeaters will become independent of their parents. This means they will not be removed before their parent is re-run. If nesting is wanted, use ```js Causality.repeat( repeaterActions, {dependentOnParent: true}); ``` `obj.observe(listener)` has been replaced with a single `obj.onChange` callback. Enable events with config `{sendEventsToObjects: true}`. It is also possible to globaly observe events by setting onEventGlobal in the configuration. You can also intercept reading and writing to any object in the world by setting onReadGlobal and onWriteGlobal in the configuration. That can be useful for security features. Observed object causality metadata are now gathered in a configurable property, defaulting to `causality`. `obj.__id` is now `obj.causality.id`. `obj.__target` is now `obj.causality.target`. Check if an object is an observable by checking for `obj.causality`. # React Integration It is fairly simple to integrate causality with react. The only thing you have to do is to run all render functions wrapped in invalidateUponChange. If change occurs, register the react component as dirty, and later, when all model changes are finished, we run forceUpdate on all dirty components. There will be a package for this purpose, perhaps later this year. # Community For discussions, see: https://gitter.im/causalityjs/Lobby For discussions in Swedish: https://gitter.im/avantgarde_web_development/Lobby # Comparison to MobX Causality is comparable to MobX. Some perhaps non-conclusive experiments indicate that causality could potentially be almost twice as fast as MobX. Causality also takes full advantage of ES6/proxies which makes it comparable to MobX version 5 and above. Causality also offers some experimental features that can not be found in MobX, such as data structure rebuilding using rebuild keys. On the other hand, MobX is a more mature library with a large supporting community and better integration with other libraries. # Context Causality is to be a foundation to an isomorphic application framework called "liquefy" that will feature full stack data binding and reactive programming (https://github.com/erobwen/liquid). It is useful to anyone that would like to do reactive programming in Javascript (https://en.wikipedia.org/wiki/Reactive_programming).

近期下载者

相关文件


收藏者