Open micahlisonbee opened 9 years ago
So you're not showing 1000 objects on one page? If not, I would probably try to handle the pagination stuff outside rivets, and then bind in chunks as you said. The whole thing about Rivets is that it is intimately entwined with the DOM, which we all know is one of the biggest bottlenecks on the web. So anything Rivets does will hit this bottleneck.
you can also bind while the html is still in memory in a document fragment then append when all the work is done.
something like.
function renderView(selectorForThisView, viewModel, viewController) {
var $viewClone = document.querySelector(selectorForThisView).cloneNode(true);
// toggle some loading state
rivets.bind($viewClone, { model : viewModel, controller : viewController });
document.querySelector(selectorForThisView).innerHTML = $viewClone;
// remove the loading state
}
We do this with Backbone in all of our apps, it makes the initial bind feel almost instant.
That should help you allot, but as @Leeds-eBooks says, you will always have issues when you have that much stuff going on.
@Duder-onomy thanks for the suggestion but my implementation of your example is about the same speed as a regular bind. Am I doing anything wrong?
renderView('#track-grid', {tracks: tracksPage.allTracks});
function renderView(selectorForThisView) {
var $viewClone = document.querySelector(selectorForThisView).cloneNode(true);
rivets.bind($viewClone, {tracks: tracksPage.allTracks});
document.querySelector(selectorForThisView).innerHTML = $viewClone.innerHTML;
}
@Leeds-eBooks no we are not showing 1000 objects on the page. We are pulling all 1000 objects into the DOM then a jQuery pagination tool paginates them. Yes handling pagination outside of the DOM (server side) would probably be best but its not possible currently.
I find that use rv-text="variation.track.name"
instead of {variation.track.name}
helps a lot too.
@woozyking Good idea.
Also, I was thinking about this more.
If there are a TON of bindings inside of a massive iterable, then performance will always be an issue. That being said, we can always manage how this performance appears to the user. If the user can at least know something is going on, then that might be enough to satisfy them. This might be a way to achieve this.
* NOT SURE IF THIS WILL WORK * Rivets binders will fire in the order they are found in the DOM. There is a 'priority' attribute that can be used on binders. The higher the priority of the more likely it will be to fire first. That being said, what if we used a super low, possibly negative value on the binder priority, essentially forcing it to fire last. Then we would know when the final binding is complete. This will let us show some sort of loading state while the view is binding.
The binder might look like,
rivets.binders['finished-binding'] = {
priority : -1000 // force it to fire last
bind : function() {
// toggle some model property or fire some event.
},
routine : function() {},
unbind : function() {}
}
the use might look like
<div rv-each-thing='model.things' a bunch of other binders rv-finished-binding></div>
Just a thought. It might work. I will repost here with a fiddle when I have time to make one. Around lunch time probably.
@woozyking thanks for the suggestion, though I didn't see any improvements by changing to rv-text="..."
. I had about 15 instances that I changed in my template...
@micahlisonbee that's bad to hear. I always find that the use of template tags makes the rendering seems slower, sometimes very noticeable that you can see those { value }
every where on the page before they get populated.
Without solving the fundamental performance issue of iterating over a large array of data, I hope there will be some form of event that can fire on rendering
and rendered
, so that we can at least add some UI components to indicate that the page is not fully loaded (like a toast or spinner).
@micahlisonbee i'm starting to look into rivets performance and i'd like to use your example to find possible bottlenecks
Can you post the json schema of your data? You can get it by posting a sample of actual data at http://jsonschema.net/
Also if layout has changed since the original post, please resend the HTML binding
@blikblum please note, this schema is overly bloated and confusing and was going to be re-written.
However, I've since changed my architecture to generate the HTML on the server, it was a huge performance improvement.
Here's the schema that should match the original HTML above (more or less):
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://jsonschema.net",
"type": "object",
"properties": {
"mood": {
"id": "http://jsonschema.net/mood",
"type": "string"
},
"direct_path": {
"id": "http://jsonschema.net/direct_path",
"type": "object",
"properties": {
"wave_canvas": {
"id": "http://jsonschema.net/direct_path/wave_canvas",
"type": "string"
},
"wave_default": {
"id": "http://jsonschema.net/direct_path/wave_default",
"type": "string"
},
"wave_progress": {
"id": "http://jsonschema.net/direct_path/wave_progress",
"type": "string"
},
"download_path": {
"id": "http://jsonschema.net/direct_path/download_path",
"type": "string"
},
"audio": {
"id": "http://jsonschema.net/direct_path/audio",
"type": "string"
},
"watermarked": {
"id": "http://jsonschema.net/direct_path/watermarked",
"type": "string"
}
}
},
"variations": {
"id": "http://jsonschema.net/variations",
"type": "object",
"properties": {
"count": {
"id": "http://jsonschema.net/variations/count",
"type": "integer"
},
"tracks": {
"id": "http://jsonschema.net/variations/tracks",
"type": "array",
"items": []
}
}
},
"tag_list": {
"id": "http://jsonschema.net/tag_list",
"type": "string"
},
"genre": {
"id": "http://jsonschema.net/genre",
"type": "string"
},
"tempo": {
"id": "http://jsonschema.net/tempo",
"type": "string"
},
"instrument": {
"id": "http://jsonschema.net/instrument",
"type": "string"
},
"industry": {
"id": "http://jsonschema.net/industry",
"type": "string"
},
"track": {
"id": "http://jsonschema.net/track",
"type": "object",
"properties": {
"stems": {
"id": "http://jsonschema.net/track/stems",
"type": "string"
},
"tracklength": {
"id": "http://jsonschema.net/track/tracklength",
"type": "string"
},
"inactive": {
"id": "http://jsonschema.net/track/inactive",
"type": "boolean"
},
"apikey": {
"id": "http://jsonschema.net/track/apikey",
"type": "string"
},
"audio_content_type": {
"id": "http://jsonschema.net/track/audio_content_type",
"type": "string"
},
"geokey": {
"id": "http://jsonschema.net/track/geokey",
"type": "null"
},
"name": {
"id": "http://jsonschema.net/track/name",
"type": "string"
},
"staff_pick": {
"id": "http://jsonschema.net/track/staff_pick",
"type": "null"
},
"audio_file_size": {
"id": "http://jsonschema.net/track/audio_file_size",
"type": "integer"
},
"audio_file_name": {
"id": "http://jsonschema.net/track/audio_file_name",
"type": "string"
},
"lyrics": {
"id": "http://jsonschema.net/track/lyrics",
"type": "string"
},
"bpm": {
"id": "http://jsonschema.net/track/bpm",
"type": "string"
}
}
}
},
"required": [
"mood",
"direct_path",
"variations",
"tag_list",
"genre",
"tempo",
"instrument",
"industry",
"track"
]
}
Thanks. It will be used just as a benchmark test. I will post the perf tests here as are done.
I have to adapt the schema to get working. Here's the codepen: http://codepen.io/blikblum/pen/eJKOXo/?editors=1010 Here's the jsperf: http://jsperf.com/rivetsjs-heavy-rendering/2
Hey Everyone in here,
Very excited to say, A negative binder priority actually works!
So this means we can implement an rv-cloak
to prevent the FOUC.
Here is a gist I made demonstrating with a rv-each
with 10,000 items.
rivets.binders.cloak = {
priority : -1000,
bind : function(el) {
el.style.opacity = 1;
}
}
This important bits about the rv-cloak binder.
[rv-cloak] {
opacity: 0;
transition: opacity 0.5s ease;
}
I'm rendering an array of of about 1000 objects. The html bindings are very heavy (see below). It's taking about 5 seconds to
rivets.bind()
.Any suggestions on improving performance? I don't think I can afford to bind in chunks as I'm using a pagination/sorting library in conjuction that needs the entire array in order to sort/paginate.
Here is my HTML for each object (tracks):