-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add $index() to the context for each item #1
Comments
See this: http://jsbin.com/tifadi/1 compared with the original http://jsbin.com/dakihezega/2 with regards to the referenced commit above. I did a long post to describe what I was going to attempt following my previous attempt at tracking indexes with the |
Sorry I keep doing commits without my user information and it bugs me so I recommitted and did a force push! As in the commit message:
Also it is not thoroughly tested although seems to work and passes tests. It leaves me questioning how the current foreach binding keeps track of item indexes |
Thanks @AdamWillden - Sorry you lost your post; I see what you're doing here, and I think it's the right idea. The performance here could be substantially improved by taking the index update outside the var lowestUpdatedIndex = this.stateItemList.length;
ko.utils.arrayForEach(this.changeQueue, function (changeItem) {
self[changeItem.status](changeItem.index, changeItem.value);
lowestUpdatedIndex = Math.min(changeItem.index, lowestUpdatedIndex);
});
for (var listLen = this.stateItemList.length; lowestUpdatedIndex < listLen; lowestUpdatedIndex++) {
this.stateItemList[lowestUpdatedIndex].$index(lowestUpdatedIndex);
} At least, I think that's roughly the idea of an The best performance for index calculation is always going to be an issue ( That said, I was hoping there might be a way to make indexes lazy i.e. perform the updates to the indexes only when something is subscribed to a I thought about making this an option e.g. It'd be great to have some tests of this $index variable. Cheers |
I had passed comment on your idea regarding adding a flag/option in my lost post. I appreciate the desire to have it 100% compatible but I also think this is a different binding and an opportunity to 'do better'. So long as the users have the ability to enable the same functionality. Depends on the final goal. Would you hope to port this code into the core if it were a straight swap? I don't know why I didn't consider just recalculating using a I tried looking at how the |
We shouldn't even need to do a |
Oh sorry now I've re-read your proposal I see you're already suggesting that to some degree. I'm catching up slowly 👍 |
Thanks Adam! This probably won't get merged into KO proper until this works with IE6 (for the 3.x series), or in a future KO release when IE6 (and maybe IE7) support is dropped. I speculate that'll probably be KO 4.x+. One of the key reasons for KO's popularity on some really big sites is the breadth of browser support, so there is a reluctance to deprecate. That said, there are a lot of issues filed about the current Incidentally, this is where the builtin I believe the builtin |
Thanks for sharing your vision for this binding. I should add that I don't personally need this I'll try and get some tests done for this |
Just a thought to add here: In 99% of my development I find myself using $index observable for 3 use cases: checking it for 0; checking it for [length-1]; checking it for odd/even. To go even further, as I can emember I've never been in a situation where I needed the $index for other use case, doesn't seem to be reasonable to check it for being equal to, let's say 541. Probably we could offer such kind of context observables like $isFirst, $isLast, etc. Seems to be much easier and efficient to implement. As for the standard $index feature, I can't imagine currently a more efficient way than what's described in the first post here by @brianmhunt. If there is any, it most likely would add a lot of complexity. |
Great thought, @cervengoc – #24 |
I was thinking a bit more about this topic. What exactly is expensive about updating observables? I mean I don't think that O(n) should matter. There is no rerendering, only if a developer binds $index in some fancy way. The most expensive seems to be the retrieval of the context, but that can be worked around by holding all $index observables in an array similar to lastNodesList, and put only a reference to these observables in each context on addition. This way the indexes could be maintained in that array (inserting new ones, updating them, etc.) I think that observables are assigned by reference, but correct me if I'm wrong. I hope it makes any sense, sorry for just flushing my raw thoughts without too much precision :) |
Thanks @cervengoc I am not averse to an O(n) implementation of One option that could significantly improve performance is to debounce the index recalculation. |
The best way would be to keep it silent by detecting if there is any subscription to it. I will have a look at it in the near future. |
Thanks @cervengoc Having previously given it a bit of thought, I believe a "pull" model where dependencies are silent until subscribed to may be more complex than "pushing" the index updates out on changes. That said I'm open! 😁 |
Is Here's an edited version of your jsbin in the README.md: http://jsbin.com/tuzuwepuya/edit?html,js,output |
Thanks @4ver – good catch. The problem occurs when the last node of a template is a text node, which does not have |
Great! Thanks @brianmhunt |
@4ver fixed in 0.5.2 🎉 Thanks so much for taking the time to report the issue! |
The current implementation looks to be either
O(2^n)
orO(n^3)
(depending on what you are measuring). In either case the defaultforeach
is practically unusable for larger lists (> 3000 items).It looks like the fastest we can get an automatically updated
$index
in the average case isO(n)
(more precisely,O(n/2)
for random indexes). My thinking is after theprocessQueue
finishes the changes to call a function something like this:where each context has a plain observable
index
, andfromIndex
is the lowest index that has been added or deleted in theprocessQueue
. It feel like it would be desperately difficult to improve the performance of this while maintaining synchronicity with the rendering and consistency, but I would welcome being shown otherwise.I mulled a dependency chain that automatically updated (e.g. each
index
be computed from a prior) but in the simple cases that leads to either challenges with performance (using apureComputed
) or memory management (using a `computed), and generally incurs a substantial overhead and adds lots of needless complexity.The case where the dependency chain is substantially faster is when there are no subscribers to the
$index
properties and so no calculations occur. We could add a flaguseIndexes
or monitor the subscriber count of the$index
properties and only run the index recalculation when there are subscribers.I believe that without the
$index
recalculation, our adds and deletes shall beO(1)
, so it is worth considering how we might (or might not) include anO(n)
$index
.The text was updated successfully, but these errors were encountered: