gerich-home / it-depends Goto Github PK
View Code? Open in Web Editor NEWLightweight dependency tracking library for JavaScript
Home Page: http://it-depends-js.github.io/
License: Other
Lightweight dependency tracking library for JavaScript
Home Page: http://it-depends-js.github.io/
License: Other
When underlying promise in promiseValue
is rejected, promiseValue
should start throwing exception on access.
We should prevent observable changes in computeds
Typings are generated during the build now.
We need to publish them to the https://github.com/typings/registry so that it will be possible to run typings install it-depends
, then edit your tsconfig.json
in the following way:
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"noImplicitAny": false,
"sourceMap": false
},
"files": [
"index.ts",
"typings/main.d.ts"
]
}
and get compile error
index.ts(6,36): error TS2345: Argument of type '() => number' is not assignable to parameter of type 'ICalculator<string>'.
Type 'number' is not assignable to type 'string'.
when running tsc
for the following index.ts
file:
import * as itDepends from 'it-depends'
var x = itDepends.value<number>(1);
x.onChange(()=>x.write(2));
var y = itDepends.computed<string>(()=>{
return x();
});
I tried to install typings from local filesystem and they work great!
Just run smth like typings install it-depends=file:..\it-depends\out\definitions\it-depends.d.ts --save
and it will generate typing file similar to this: https://gist.github.com/gerich-home/c23f5c81c1d5bd0c39df6cba5d68029c
We just need to automate it for release process.
I have typescript lint error in https://github.com/gerich-home/it-depends/blob/master/src/computed.ts#L153 line (ISubscription is not assignable to type {Function, Function}
).
self.onChange = function(handler: IComputedValueChangeHandler<T>): ISubscription {
Actually, I don't have experience in TypeScript language. But after a little investigation I found that
export type IComputed<T> = IComputedValue<T> | IWritableComputedValue<T>
line is cause of the error. So, here is union operator with different constructors. So, my question is: Does it depend on version of TypeScript? Do you have an error there like me?
Sometimes the list of all computed values in your program is not known apriori.
In that case you have to create an array that will store computeds for each value.
There is an idea to introduce parametric computeds. You will be able to "curry" some parametrs that will be passed to your computed.
The calculated value will be cached and associated with the passed parameters
var c = itDepends.value(1);
var d = itDepends.computed(function(a, b) {
return Math.sqrt(b*b - 4*a*c());
});
console.log(d(2, 1)); // calculation
console.log(d(2, 1)); // cached value
console.log(d(10, 5)); // calculation
console.log(d(10, 5)); // cached value
console.log(d(2, 1)); // cached value
c(2);
console.log(d(10, 5)); // calculation
console.log(d(2, 1)); // calculation
console.log(d(2, 1)); // cached value
Concerns
Parametric syntax conflicts with writable computed syntax. Idea is to make a breaking changeand introduce explicit write method
There should be also some kind of curry method, so you will be able to get the child computed with fixed set of parameters
var d21 = d.with(2, 1);
console.log(d21());
Use gulp-tslint. Configure rules, fix source code to follow it:
https://github.com/gerich-home/it-depends/tree/tslint
There should be an ability to compare performance of certain scenarios (not versus KnockoutJS)
For example I know at least 2 tests I want to write that way.
Given the following definitions:
var x = [];
for (var j = 0; j < dependenciesCount; j++) {
x.push(itDepends.value(-1));
}
var a = itDepends.computed(function() {
var z = 0;
for (var j = 0; j < dependenciesCount; j++) {
z += x[j]();
}
return z;
});
var b = itDepends.value(true);
var c = itDepends.computed(function() {
return b() ? a() : 0;
});
the scenario:
itDepends.bulkChange(function() {
c.onChange(function() {});
b.write(false);
});
should work faster than scenario with approximately the same performance as in the following scenario (see #68):
c.onChange(function() {});
b.write(false);
Given the following definitions:
var x = [];
for (var j = 0; j < dependenciesCount; j++) {
x.push(itDepends.value(-1));
}
var a = itDepends.computed(function() {
var z = 0;
for (var j = 0; j < dependenciesCount; j++) {
z += x[j]();
}
return z;
});
var b = itDepends.value(6);
var c = itDepends.value(10);
var d = itDepends.computed(function() {
return b() * c() === 60 ? a() : 0;
});
var s = d.onChange(function() {});
the scenario:
itDepends.bulkChange(function() {
b.write(4);
c.write(15);
});
should work faster than scenario:
b.write(4);
c.write(15);
There should be an ability to write:
var a = itDepends.value(10);
var b = itDepends.value(20);
var c = itDepends.computed(function() {
return a() + b();
});
var subscription = c.onChange(function(newValue, oldValue) {
console.log(oldValue + ' -> ' + newValue);
});
a(20); // outputs 30 -> 40
b(30); // outputs 40 -> 50
itDepends.bulkChange(function() {
console.log('start');
a(30);
b(40);
console.log('a = ' + a());
console.log('b = ' + b());
console.log('end');
}); // outputs start, a = 30, b = 40, end, 50 -> 70
a(40); // outputs 70 -> 80
b(50); // outputs 80 -> 90
Write documentation as a set of .md files and generate Jekyll website from them during the build.
Discuss and implement
During creating new Appveyor build I faced out with issue - I could not pass a build with unit-tests
gulp task because it depends on coveralls
task which should be configured for appveyor build previously. I am proposing move coveralls
task somewhere to be executed after unit-tests are done.
Write test to prove it, fix, document
There should be an ability to build lazy computed collections
Gather coverage during in CI. (use gulp-coverage task)
Attach report as an AppVeyor artifact.
Publish coverage data to coveralls
Instead of
var a = itDepends.value(10);
a(15);
I want to write
var a = itDepends.value(10);
a.write(15);
See #7 for why.
There should be an ability to get "writer" to allow old syntax
var aWriter = a.write();
aWriter(15);
I created comparing tests with knockout. Only for observables for now. - http://jsperf.com/knockout-vs-itdepends/5 . Writing new values to observables without subscribers works fast (check here http://jsperf.com/knockout-vs-itdepends/7). Much much better then knockout observable. But only with one subscriber it works a bit slower.
Performance is being reduced during increasing number of subscribers. - http://jsperf.com/knockout-vs-itdepends/6
Should we generate them during build phase? Discuss and implement if needed
There should be an ability to write:
var a = itDepends.value(10);
var b = itDepends.computed(function() {
return a() > 30 ? 30 : a();
});
var subscription = b.onChange(function(newValue, oldValue) {
console.log(oldValue + ' -> ' + newValue);
});
a(20); // outputs 10 -> 20
a(30); // outputs 20 -> 30
a(40); // outputs nothing
subscription.disable();
a(20); // outputs nothing
subscription.enable();
a(10); // outputs 20 -> 10
It would be good to have typings bundled with node package to do not force users of library to use external typing mechanism (such as typings/tsd)
http://www.typescriptlang.org/docs/handbook/typings-for-npm-packages.html
AppVeyor yields quite a different results that local performance tests:
https://ci.appveyor.com/project/gerich-home/it-depends/build/1.0.220
Compare to local run on my machine:
'subscribe to computed with 1000 subscribers and unsubscribe them' 1.05x slower 'subscribe to computed with 1 subscribers and unsubscribe them' 1.40x slower 'subscribe to computed with 3 subscribers and unsubscribe them' 1.14x slower 'subscribe to computed with 500 subscribers and unsubscribe them' 1.01x faster 'computed updated 1000 times with 1000 subscribers' 2.09x faster 'computed updated 1000 times with 1 subscribers' 2.73x faster 'computed updated 1000 times with 500 subscribers' 2.62x faster 'computed updated 1 times with 1000 subscribers' 10.05x faster 'computed updated 1 times with 1 subscribers' 10.42x faster 'computed updated 1 times with 500 subscribers' 10.05x faster 'computed updated 3 times with 1000 subscribers' 2.20x faster 'computed updated 3 times with 1 subscribers' 1.50x faster 'computed updated 3 times with 500 subscribers' 2.22x faster 'computed updated 50 times with 1000 subscribers' 2.15x faster 'computed updated 50 times with 1 subscribers' 1.83x faster 'computed updated 50 times with 500 subscribers' 2.29x faster 'read observable 1000 times' 2.43x faster 'read observable 100 times' 2.03x faster 'read observable 1 times' 1.92x faster 'subscribe to observable with 1000 subscribers and unsubscribe them' 1.09x slower 'subscribe to observable with 1 subscribers and unsubscribe them' 1.30x slower 'subscribe to observable with 3 subscribers and unsubscribe them' 1.19x slower 'subscribe to observable with 500 subscribers and unsubscribe them' 1.09x slower 'write observable 1000 times with 1 subscribers' 12.82x faster 'write observable 1000 times with 3 subscribers' 8.28x faster 'write observable 1000 times with 50 subscribers' 2.62x faster 'write observable 1 times with 1000 subscribers' 9.91x faster 'write observable 1 times with 1 subscribers' 10.32x faster 'write observable 3 times with 1000 subscribers' 1.83x faster 'write observable 50 times with 1000 subscribers' 1.87x faster
Slow tests are significantly slower than on my local machine (up to 5.5 times), while fast tests are significantly faster (up to 72 times).
Thus AppVeyor results are not representative. What I see is that the deviation is much higher on AppVeyor (up to +-40%) when on my local machine it is quite slow (up to +-4.5%).
This behavior needs further investigation.
One can compare the behavior on AppVeyor and some alternative CI server (TravisCI?)
They are not recalculated when some dependencies are changed
Need to discuss if it is needed for .Net projects to publish to NuGet.
It will be good to have a set of examples for the whole API.
Examples can be written in some tools like Tonic (https://tonicdev.com/gerichhome/it-depends), JsFiddle and etc.
3.2.0 was published from non master branch by mistake. It should not happen any more
Need to have a way to know that any observable value just changed (in general)
Simalar to #3, but it will give you the way to do not subscribe to the concrete observable value, but subscribe just to the general event.
var a = itDepends.value(10);
var b = itDepends.computed(function() {
return a() > 30 ? 30 : a();
});
var c = itDepends.value(10);
var subscription = itDepends.onChange(function(value, from, to) {
console.log('a: ' + (value === a) + ' (' + from+ ' -> ' + to + ')');
});
a(20); // outputs a: true (10 -> 20)
a(30); // outputs a: true (20 -> 30)
a(30); // outputs nothing
c(20); // outputs a: false (10 -> 20)
a(40); // outputs a: true (30 -> 40)
subscription.disable();
a(50); // outputs nothing
subscription.enable();
a(60); // outputs a: true (50 -> 60)
disable should not keep the registration in the library, so when you disable and throw away the reference to subscription it gets garbage collected
See test from ee7a353
Perf results on my local machine are:
'computed diamond updated 1000 times with 500 hidden dependencies'
'knockout' is etalon
'itDepends' at 1066.24x slower
When computedValue
depends on itself it should throw exception unless the cycle is destroyed by a change of some dependency.
Avoid repetitive calls to computed function if exception has been thrown.
Rethrow exception that was called on the calculation.
Allow recalculation when some of dependencies was changed.
Take a look into using something like gulp-umd to create and UMD wrapper for a library instead of placing all the code in one file
In certain situations there is no point in subscribing or unsubscribing immediately.
We should postpone deep subscriptions until a change was made.
For the case of bulkChange
subscriptions/unsubscriptions should be postponed until the end of bulk change.
Given the following definitions:
var x = [];
for (var j = 0; j < dependenciesCount; j++) {
x.push(itDepends.value(-1));
}
var a = itDepends.computed(function() {
var z = 0;
for (var j = 0; j < dependenciesCount; j++) {
z += x[j]();
}
return z;
});
var b = itDepends.value(true);
var c = itDepends.computed(function() {
return b() ? a() : 0;
});
the following scenarios should work with approximately the same performance:
c.onChange(function() {}); // triggers massive subscriptions currently
b.write(false); // but all of them get disabled here
b.write(false);
c.onChange(function() {});
Given the following definitions:
var x = [];
for (var j = 0; j < dependenciesCount; j++) {
x.push(itDepends.value(-1));
}
var a = itDepends.computed(function() {
var z = 0;
for (var j = 0; j < dependenciesCount; j++) {
z += x[j]();
}
return z;
});
var b = itDepends.value(false);
var c = itDepends.computed(function() {
return b() ? a() : 0;
});
var s = a.onChange(function() {});
x[0].write(1);
the following scenarios should also work with approximately the same performance:
s.disable(); // should not unsubscribe from a and all x[i] immediately!
var s2 = c.onChange(function() {}); // because the replacement subscription is created here
b.write(true); // but becomes active only here
var s2 = c.onChange(function() {});
b.write(true);
s.disable(); // does not trigger massive unsubscriptions currently
There should be an ability to create an object with computed fields and observable values with fancy syntax.
Writable computed can be used to encapsulate the logic of modifing its value, so it is vital to have such an ability
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.