-
Notifications
You must be signed in to change notification settings - Fork 21
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
Performance #35
Comments
Hi! Glad you like FRZR and welcome aboard! 👍 Yeah, I'm aware of some bottlenecks, but I've ranked simplicity higher than micro-optimizations. There's no end of adding this and that here and there. Suddenly you have a big bloated framework, where all the abstractions are actually what make it slow. Having said that, I agree with you, that el.extend could be more efficient - although I actually quite rarely use it myself. I don't actually even use I check out your PR in a moment - I just got back from paragliding and have to take a little rest 😁 |
Btw. have you seen my presentation about the concepts behind FRZR: https://youtube.com/watch?v=0nh2EK1xveg 😉 There's of course some special details not mentioned, for example |
I was watching it yesterday, that was what got me to mess around here :). I'm looking for a view library that's as tiny as possible for one project of mine where I'm already packing a 700KB of Pixi.js for canvas rendering, and the actual DOM UI I've planned is not enough to pack Vue or React on top of that (plus I think both of those, are bloated monsters already). |
I agree with you. With FRZR your bundle can actually quickly become smaller than even with vanillajs, if you think about how many createElement/setAttribute/etc you don't have to type 😄 And I still have tried to abstract as little as possible. So it's more futureproof also in a sense.. But comparing frameworks / libraries is not that useful - each one serves or have served it's purpose. |
If you have any questions about FRZR, don't hesitate to ask - I'm happy to help and it's good to gain insight which things are easy to use use and which not.. 😎 Documentations suck right now and there's not enough examples, I should enhance that. If only there would be more hours in a day 🤔 |
I think I can get my way around it by just reading through the source code 🤓. Just goofing around, with some specialisation you can drop numbers quite a lot:
This is using the assumption that the first child of the |
One big question with microbenchmarks is, that does the compiler have a chance to optimize the code or not.. Usually it will take some time to get an app to run at full speed. After the optimizations things can get faster without the extra tweaks. For example I just read an article that in most cases caching an array length is slower after optimizations, because compiler can't optimize it as far as without. And the better the compilers get, less the need for micro-optimizations.. |
Also when you have long execution chains, having an extra code can hit the overall performance as well.. |
I'm no expert of the compilers though, but I know FRZR's rate of performance/simplicity is already pretty good.. I'm not making the fastest library around, but the most minimalistic and all-around performant as possible. |
But I will check out your PR in a moment and of course there's room for lots of further improvements 😎 |
V8 is a hell of a VM, but it's not magic. You usually get the full benefits after few iterations (< 10), I'm benchmarking everything with a 1,000,000, if only to get proper granuality to measure nanoseconds ( My general experience is that people in JavaScript world assume too much and benchmark too little 🙂. A recent example - I've seen a claim that creating a On that note, V8 can do absolutely nothing about WebAPIs (so, basically the entire DOM), it doesn't even know they exist. To V8 they are just some FFI C bindings it has to call and wait for. Calling Making the execution chain longer can stop V8 from inlining functions, and when that happens, a microbenchmark will pick it up. It can also be remedied by putting the expensive but rare control path behind a different function call :). But I digress... Also I don't want this whole thing to seem like I'm picking on FRZR being slow, it's very, very decent! I wouldn't want to go super crazy over this and start breaking everything down into specialized if / else hell to squeeze up every single nanosecond possible, that is a kind of madness of it's own, simplicity has to prevail! There are usually few low hanging fruits that are easy to kick over for a big boost. The Ok, this ended up being way too long! Need to cook some food. |
Yeah, I've seen it also, just always thought it's ugly :) But let's go with it! |
Btw. why did you choose six "cached" arguments? :D |
No particular reason other than that I like "counting" to |
With that last PR reversing 10000 elements with FRZR now benchmarks at ~75ms, while React is at ~120ms on my hardware 😎. I reckon you have a better idea what the numbers were before. |
That's great! I made a pull request to update the dbmon as well. It's at least as fast as it was (was already quite old version, which was probably simplier).. |
I'm so glad you came aboard – such great pull requests coming through! 👍 |
Ok, I think I just broke the internet. I've been goofing around with different kinds of proof of concept implementation of syntax similar to FRZR. Tests: bench('Vanilla JS', function() {
var div = document.createElement('div');
var h1 = document.createElement('h1');
h1.className = 'V_JS';
h1.textContent = 'Hello ';
var b = document.createElement('b');
b.textContent = 'V_JS';
h1.appendChild(b);
h1.appendChild(document.createTextNode('!'));
var p = document.createElement('p');
p.textContent = 'Bacon ipsum dolor amet meatloaf meatball shank porchetta \
picanha bresaola short loin short ribs capicola fatback beef \
ribs corned beef ham hock.';
div.appendChild(h1);
div.appendChild(p);
return div;
});
bench('DOOM <div> with multiple child nodes', function() {
div(
h1(setClass('doom'), 'Hello ', b('DOOM'), '!'),
p('Bacon ipsum dolor amet meatloaf meatball shank porchetta \
picanha bresaola short loin short ribs capicola fatback beef \
ribs corned beef ham hock.')
);
});
bench('FRZR <div> with multiple child nodes', function() {
frzr_div(
frzr_h1({ className: 'frzr' }, 'Hello ', frzr_b('FRZR'), '!'),
frzr_p('Bacon ipsum dolor amet meatloaf meatball shank porchetta \
picanha bresaola short loin short ribs capicola fatback beef \
ribs corned beef ham hock.')
);
}); Benchmark results on Chrome Canary:
So basically as fast as vanilla implementation, sometimes faster! Here is how it works: All the tag functions are constructed by bindings, like so: var b = expand.bind(el('b'));
var div = expand.bind(el('div'));
var h1 = expand.bind(el('h1'));
var p = expand.bind(el('p'));
The whole content of export function expand() {
var el = this.cloneNode(false);
var hasChildren = false;
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (typeof arg === 'string') {
if (hasChildren) {
el.appendChild(document.createTextNode(arg))
} else {
el.textContent = arg;
hasChildren = true;
}
} else if (arg.nodeType) {
el.appendChild(arg);
hasChildren = true;
} else {
arg(el);
if (!hasChildren) {
hasChildren = el.hasChildNodes();
}
}
}
return el;
} So, instead of using
Major differences compared to FRZR:
When constructing the header like this: h1(setClass('doom'), 'Hello ', b('DOOM'), '!')
Nothing FRZR related as such, it's just my own exploratory territory, but I figured you might find the figures and more FP approach interesting. And now I'll go out and pretend I do have a life. |
I also like to explore: you can't believe how much FRZR have changed since 0.0.1 :) Also the whole way of how I develop projects have changed so many times I can't even count anymore.. But I've decided to keep the design of FRZR quite stable from now on, and prefer to create a new library instead if the whole design is a lot different. For example RZR was such an experiment (with virtual dom). I didn't like the virtual dom concept though, since you need to put keys everywhere all the time to prevent extra updates. I've actually also thought about creating a bit more "pure" version of FRZR. Not with virtual dom, but quite something you showed. Let's see. Also the frzr-dom needs rethinking. Instead of faking the It's really exciting to fiddle around with new ideas, even if they are dumb sometimes – in the end you might invent something great! ;) |
Too many people just say:
I like you're kind of people more, who like to try new things and love minimalism! 😎 |
Although when the author of Mithril.js says kind words about your library, you know you're doing something right and you learn to ignore the nonsense :D |
Oh, now I realized what you're doing with that |
Yep. Making a big library is not really a problem, it's making a small library that still does everything you need and not letting it bloat over time that's the challenge. I'm using React at work now, things are easier when people jump at the code base and are familiar with the ways things are built because they have seen it before - but that's really all there is to it. The code behind it matters little. I have a love / hate relationship with virtual dom. The nerdy side of me likes it for being all automagical, the concept as such is really really brilliant... but... DOM updates are not video game rendering on a bitmap, simple bindings solve the problem easier, faster and with much, much less code. And then you have smaller but still considerably sized libs like Vue which does the update bindings for you, but suddenly things are magical and you don't really have any control over the (leaky) abstractions. |
I know exactly what you mean. |
Related to #34
I really, really like this library! People tend to forget that simplicity is how you make elegant code, not abstraction.
That said looking through the source code I've found some potential bottle necks. There are few places where a happy-path optimiziation for most-common patterns can save few hundred nanos.
I've made a very rough implementation with a limited feature set (name very temporary), and this is what I'm getting:
Numbers for FRZR don't have the
el.extend
from the PR. It's going to be hard to retain all functionality with that level of performance, but it should be easily possible to go into < 1500ns area.I'm aware nanosecond benchmarking in JavaScript is a pretty exotic sport, but it only takes 200 DOM elements (and let's be honest, most complex apps create much more) to block the thread for a full millisecond with FRZR, and that's without any attributes or child element mounting etc.
The text was updated successfully, but these errors were encountered: