googlearchive / observe-js Goto Github PK
View Code? Open in Web Editor NEWA library for observing Arrays, Objects and PathValues
A library for observing Arrays, Objects and PathValues
When items are added or removed from array being watched by ArrayReduction, all the PathObservers that watched items indexed AFTER the add/remove index are out of sync.
Let's look at an example...
var values = ['a','b','c'];
var calls = [];
var reduction = new ArrayReduction(
values,
'',
function(sum,cur){
sum.push(cur);
return sum;
},
calls
);
calls.splice(0);
// Internal view of observers.path for each item by index:
// array index observer.path
// ----------- -------------
// 0 0
// 1 1 <---- To be spliced
// 2 2
values.splice(1,1);
reduction.deliver();
// Internal view of observers.path for each item by index:
// array index observer.path
// ----------- -------------
// 0 0
// 1 2 <---- INCORRECT PATH, SHOULD BE 1
// == EXPECTED ==
// > Calls to reduce function: ["a", "c"]
// === ACTUAL ===
// > Calls to reduce function: ["a", "c", "a", "c", undefined]
console.log('Calls to reduce function:', calls);
... Notice the difference in EXPECTED
and ACTUAL
output.
What appears to be happening is the PathObserver that was watching the [2]
element (which is now the [1]
element), incorrectly causes a another reduce()
because it sees a change in value ('c'
-> undefined
).
I believe the problem is that ArrayReduction's handleSplice()
does not loop over and update the paths in observers
. https://github.com/rafaelw/ChangeSummary/blob/08cb2c69b5daba0cbd5e806820311a76ea279858/util/array_reduction.js#L56
This issue is relevant only when Object.observe is unavailable.
The topeka app takes ~12ms to do a no-op dirty check in Safari and ~45ms on an iPad. This was determined by timing Platform.performMicrotaskCheckpoint
within Polymer's dirty check interval when the app was idle. This jsperf suggests that dirty checking polymer's observed property getters is particularly slow. A quick test to comment out most of the work done in these getters improved the dirty check time by ~33%. Note also that Topeka has about 1200 observers, as reported by Observer._allObserversCount
.
What is Observer.createBindablePrototypeAccessor
used for? Is it being called anywhere in the current version of observe-js?
Hey guys,
I've been playing with this lib to see if I can use it as a polyfill. I've included the observe.js and in the console created a basic object:
var a = { moo: 0 };
Then added a path observer:
new PathObserver(a, 'moo', function() { console.log(arguments); });
Then updated the object:
a.moo = 2;
Nothing gets called. I've also tried multiple different ways of doing this but no luck. Can someone point me in the right direction here? :) thank you!
The Object.observe bits are in theory a good match for implementing an observer for the new IEFT JSON Patch standard (http://tools.ietf.org/html/rfc6902).
I created an implementation of it here. I use your bits in Chrome Canary when available and dirty checking for legacy browsers. However, I get a big performance drop when resorting to the obvious Object.observe implementation.
So my question is:
Should I expect the current implementation to be early work or should I investigate the performance of the Object.observe based version of JSON Patch?
Refer to https://github.com/aheckmann/observed
does this support nested object? I think it's a useable feature.
Tested with NodeJS 0.10.28
var someObject = {
foo: []
};
observer = new ObjectObserver(someObject);
observer.open(function() {
return console.log(arguments[0]);
});
someObject.foo.push('anotherMoo');
observer.deliver();
This wont deliver anything.
var someObject = {};
observer = new ObjectObserver(someObject);
observer.open(function() {
return console.log(arguments[0]);
});
someObject.foo = []
someObject.foo.push('anotherMoo');
observer.deliver();
This delivers { foo: [ 'anotherMoo' ] }
as added
I suspect this is due to the fact that Object.defineProperty
wont trigger a set
when pushing into an array. The only workaround I found is to use full diffing of objects using deep-diff
Maybe on the second or third value retrieval. The cost is showing up in start-up profiles
Analogous to observeOwnChanges (https://code.google.com/p/mutation-summary/wiki/APIReference).
This is potentially expensive in the dirty-check case, so I'll wait until a specific use case arises.
https://github.com/Polymer/observe-js/blob/master/src/observe.js#L367
There is more information available on ex
then console.error
emits to the console.
Changing it to something like this:
console.error('Exception caught during observer callback: ', ex.stack || ex);
Gives a lot more useful information, on Chrome at least.
I didn't make a pull request because I didn't do any due diligence other than throw that change into my local checkout. I don't know what this does on any other browser, e.g., and I suspect Arv knows a lot about this topic.
@arv: btw, SD Polyfill has a similar issue where it rethrows a squelched error which loses the stack information. It could use the same treatment.
When an observer created by PathObserver.defineProperty is closed, currently it deletes the the bound property on the object.
This removes the property descriptor which links the property to the descriptor, but it also removes the current value of the property. It should do the former but not the latter.
Uncaught Error: Provided object is not an Array
Object.observe does not trigger changes for IDL properties (e.g. offsetWidth, etc...) so when Observe-js is using the polyfill I can successfully bind to a HTMLElement's offsetWidth. But when Observe-js is using the native Object.observe it won't get any updates for offsetWidth as it doesn't trigger changes.
Is it possible to force these properties to use the polyfill?
E.g.
ob = new PathObserver(obj, '')
ob.deliver().
PathObservers in this state should just be closed as soon as they are opened so that most of their API are noops.
i would like to receive the observed path in the path observer callback. this would make it easier for me to use a single callback to observe multiple paths
On Chrome Apps the security policy detection fix from #26 doesn't seem to work and you get:
it seems Chrome Packaged Apps don't have document.securityPolicy
defined.
Not seeing the same issue on our build with Mobile Chrome Apps, however, even though there is no document.securityPolicy
there either.
The package.json lists the name as observejs, but that appears to be a npm package written by someone else.
And take four arguments (rather than having third object be a object/path object).
Need to doc new optional arguments as well as CompoundPathObserver
especially for Object.observe, async is the normal case (not forced deliver)
not on what has changed (e.g. object vs path)
The Observer constructors all have >= 4 arguments, some of which are optional.
If it's not too bad of a performance cost, it would be nicer if the constructors took dictionaries instead.
e.g., '0' is not a valid path, but '[0]' is.
Without chrome://flags/#enable-javascript-harmony, this example simply doesn't work and chews 100% CPU in Chrome, and chews 100% CPU in Firefox + continually eats memory.
aside: also exposes a PITA regarding whitespace in templates.
<!DOCTYPE html>
<html lang="en">
<head>
<title>polymer cpu thrashing test</title>
</head>
<body>
<template id="view" bind>
<section class="path-segments">
<template repeat="{{ file, key in pathSegments}}" bind><template if="{{ file.href != path }}" bind><a href="?path={{file.href}}">{{file.text}}/</a></template><template if="{{ file.href == path }}" bind>{{file.text}}</template></template>
</section>
<input value="{{ path }}" />
</template>
<script src="/platform.js"></script>
<script>
window.addEventListener('WebComponentsReady', function() {
var model = {path: '/path/to/file'}
Object.defineProperty(model, "pathSegments", {
get: function() {
return this.path.split('/').map(function(item, index, segments) {
return {
text: item,
href: segments.slice(0, index + 1).join('/')
}
})
}
})
var viewEl = document.querySelector('#view')
viewEl.bindingDelegate = new PolymerExpressions()
viewEl.model = model
})
</script>
</body>
</html>
How to use this with a require() statement?
if I create a CompoundObserver and add a new ObjectObserver to the compound observer, changes to the observed object do not get reported (when calling deliver()
on the compound observer)
It seems the NPM package is woefully out of date. Would it be possible to update and publish to NPM? Thanks.
I think there is a bug on this line:
https://github.com/rafaelw/ChangeSummary/blob/master/util/array_reduction.js#L38
var removeIndex = splice.index;
while (removeIndex < splice.removed.length) {
observers[removeIndex].close();
removeIndex++;
}
should it be like this?
while (removeIndex < splice.index + splice.removed.length) {
Since observe-dart follows observe-js, I think it is necessary for the team to be aware of the following bug in the Dart implementation.
Cases to consider:
Path:
-empty string (currently a path with 0 property components)
-index operators, e.g. "foo[2].baz" (currently not supported)
Value at Path:
-empty string path (the value is the model itself)
-non-object model (valid, if path is non-empty, value is undefined)
When the the observe-js polyfill is used with accessor properties, changes are detected via dirty checking. Changes are not detected to accessors under Object.observe. The requirement in this case is that users call Object.getNotifier(object).notify(changes).
This should be sugared by observe-js such that there's a polyfill transparent way to do this, along the lines of:
https://github.com/Polymer/observe-js/blob/master/src/observe.js#L970
Currently it's [this.value_, oldValues, this.observed_]
.
That's insane.
Hi @rafaelw, I'm wondering what's the status of this project? Is ChangeSummary kind of production-ready? I'd like to use it like a Object.observe shim. I understand I will still need to call .deliver()
but this project seems to be more promising than any other shim I have seen so far.
Thanks again for this awesome project! Please let me know :D
The correct pattern of use may be to use lots of little ChangeSummaries, instead of a single one with lots of observations. If that is ok, the CallbackRouter probably isn't neccessary
It would be very useful to have this project broken into two parts. An Object.observe shim, and then the additional observation helper functions.
In this case, the compiled function looks like the following and tries to return a property called 'undefined' rather than the object itself:
if (obj) return obj["undefined"]; else return undefined;
Could be solved here https://github.com/rafaelw/ChangeSummary/blob/master/change_summary.js#L485 by performing this statement only if the path has non-zero length.
Right now, observing the prototype chain is semantically correct. Also, it's different with dirty-check vs Object.observe
pathTrackerCheck generates a path value getter that uses eval when available and Path.prototype.walkPropertiesFrom otherwise.
It would be useful to have that ability as a utility, something like: ChangeSummary.generatePathGetter(path)
moved from googlearchive/TemplateBinding#160
I believe the idea is to consolidate the names that observe-js is adding.
https://github.com/Polymer/observe-js/blob/master/src/observe.js#L725
the field is set to false, and it's checked in addPath, but as far as I can tell, it's never set it true. I think this should happen in "start".
https://github.com/Polymer/observe-js/blob/master/src/observe.js#L66 tries to use document.securityPolicy
to detect whether eval()
is allowed, but that attribute appears not to exist anymore in Chrome, Firefox, and Safari. Then it runs new Function('', 'return true;');
which, as the comment suggests, causes "an error message in console even when the exception is caught".
i.e. new ArrayView(array, filterFn, mapFn, sortFn)
ArrayView.prototype = {
proto: Array.prototype
}
Moved Polymer/polymer#228 to here.
node-webkit is a project that combines node.js
and Chromium
, with node.js
preloaded into the javascript vm.
node.js
uses the global
global scope, and starting at Line 1174 in change_summary.js, the use of global
will put PathObserver
and other modules into the node.js
scope and not the window
scope.
this includes paths, observedObjects and observedSets.
Objects may be created for using in observation, purely for the purpose of being observed. When they are no longer observed, the should become collectable.
This is broken in IE10.
Line 314
Path.prototype = {
__proto__: [],
This either needs to be wrapped in createObject or refactored to not use proto.
Here is createObject
from compat.js
var createObject = ('__proto__' in {}) ?
function(obj) { return obj; } :
function(obj) {
var proto = obj.__proto__;
if (!proto)
return obj;
var newObject = Object.create(proto);
Object.getOwnPropertyNames(obj).forEach(function(name) {
Object.defineProperty(newObject, name,
Object.getOwnPropertyDescriptor(obj, name));
});
return newObject;
};
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.