Skip to content
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

Why fastdom? #35

Open
oskarrough opened this issue Oct 18, 2013 · 20 comments
Open

Why fastdom? #35

oskarrough opened this issue Oct 18, 2013 · 20 comments

Comments

@oskarrough
Copy link

Fastdom sounds so efficient that I need to ask what the possible downsides are. Why is this not the default behaviour implemented in modern browsers?

you should wrap any DOM reads with fastdom.read and writes with fastdom.write. They will get batched & executed in next frame...

@paullewis
Copy link
Collaborator

The simple reason is that browsers are wired for sync ops. You can set offsetWidth (write) and then ask for its value (read) and that is allowed. FastDOM lets you opt out of that and makes everything async. That is you would get the old value of offsetWidth before the new one was set. That's one example, and there are many properties that would trigger layout that you can Google for.

Async is great, and it would be lovely if this were the normal behaviour. But things would break if this were the default. FWIW Dart actually does DOM updates async, not that it solves this issue, but just so you know there are places where async DOM updates are normal and don't require libraries like FastDOM.

@wilsonpage
Copy link
Owner

Would it be helpful to have an answer like this on the main readme?

@paullewis
Copy link
Collaborator

I think so. Setting out why this even a thing is going to help devs less familiar with the area.

@renatoi
Copy link

renatoi commented Feb 26, 2014

Sorry to resuscitate the issue but I have a question:

What's the difference between using requestAnimationFrame directly and using fastdom?

@wilsonpage
Copy link
Owner

Using rAF might be OK for very small issues, but it doesn't ensure you won't be interleaving DOM read and writes, which is the thing we want to avoid.

How can you be sure that another part of your app hasn't scheduled conflicting work for the same frame?

FastDOM 'globally' coordinates when your read/write tasks are run, meaning that they are always run in the most performant way. All you have to know is that when your callback fires, the job is done :)

@serapath
Copy link

serapath commented Feb 6, 2015

how does the performance of fastdom compare to virtualdom?

@wilsonpage
Copy link
Owner

A virtual DOM library could consume a library like Fastdom to help it
schedule operations at the correct time.

A virtual DOM library may also do a lot more. Think of fastdom as a lower
level tool and a virtual DOM library as higher level abstraction.

All performance comparisons are relative. You'd need to try for yourself.

W.
On 7 Feb 2015 03:57, "serapath" [email protected] wrote:

how does the performance of fastdom compare to virtualdom?


Reply to this email directly or view it on GitHub
#35 (comment).

@leandromoreira
Copy link

leandromoreira commented Jun 2, 2016

It might sound silly (just naming and curiosity) but why measure and mutate functions instead of read and write?

Forget about it, I think I know why.

@wilsonpage
Copy link
Owner

wilsonpage commented Jun 3, 2016

I think they are a little clearer in their intent. For example, you can 'read' an via .getAttribute() without making DOM 'measurements'. With 'mutate' I also feel it's more explicit. Sounds more damaging and should be treated with care.

@allyraza
Copy link

what I don't understand why do we need a library when browser actually queue dom operations before doing a repaint.

@paullewis
Copy link
Collaborator

paullewis commented Nov 23, 2017

@allyraza because the browser won't stop you breaking that behaviour. If you mutate some styles and then request -- say -- offsetLeft, the browser will run layout at that point. So while it's true that browsers do enqueue DOM operations, and that by default they will get applied in a batch, it's also true that you can break that behaviour with JavaScript, and that's what FastDOM is attempting to help with.

@crazy4groovy
Copy link

I see a lot of performance solutions suggest a double/inner raf, but fastdom isn't using that technique. Is there a reason? I presume it was tried and measured.

@wilsonpage
Copy link
Owner

Interesting, can you give more detail/links?

@wilsonpage
Copy link
Owner

This is a really interesting find, I've been giving it some thought. IIUC the issue is that if the DOM is manipulated outside of rAF and then you schedule a rAF with some other work inside, when browser will not actually paint the output of the DOM manipulation until that next frame, so essentially both tasks can end up running in the same frame.

So this issue is really about running blocking code inside rAF handlers delaying the browser beginning animations. I think we need a concrete example to make sense of this; so let's take clicking a navigation button, loading some data and navigating:

button.addEventListener('click', () => {
  fastdom.mutate(() => {
    button.classList.toggle('ripple');
    setTimeout(loadDataAndNavigateTo('some-page'));    
  });
});

I'm mutating the DOM and then, scheduling the loading and navigation at the end of the task queue so that is doesn't block the animation from starting. You could optionally use rAF instead of setTimeout(), but then you risk blocking other animations and render work.

This is a bit gross looking, I think I'd rather have a way to run something after the fastdom task is complete (AKA the animation has begun). Like:

button.addEventListener('click', async () => {
  await fastdom.mutate(() => button.classList.toggle('ripple'));
  loadDataAndNavigateTo('some-page');
});

That would require than we return a Promise once the fastdom task has been run, and might make this kind of use-case a bit prettier. We'd have to make sure this was after the internalrAF is fully complete.

Does that make sense? Have I understood the problem? :)

@crazy4groovy
Copy link

That's an interesting thought. Honestly I don't know enough low-level to give an opinion, but returning a "blocking" promise that resolves when the mutation is complete makes sense.

I was just looking particularly at https://github.com/wilsonpage/fastdom/blob/master/fastdom.js#L158
and wondered if fastdom.raf(fastdom.raf(flush.bind(null, fastdom))); would be more performant? I think only empirical perf tests would determine that.

@Mapiac
Copy link

Mapiac commented Mar 5, 2019

Is this still a commonly (and more so recommended) library in 2019? With render, layout and paint speeds essentially so fast and with RAF, just wondering if this great library is still recommended? Maybe the benefits of batch reads and writes persist no matter how fast V8 engine or device CPU are?

@wilsonpage
Copy link
Owner

I hope fastdom disappears over time. I wouldn't reach for fastdom without diagnosing that you have a render per issue with your app. As with everything it depends. If jank is still a think on the mobile web, then there will likely be a place for fastdom.

If the DOM is abstracted away from you via a framework like React, you probably don't need fastdom.

@Mapiac
Copy link

Mapiac commented Mar 8, 2019

Thanks. Not using any VDOM or really any frameworks @wilsonpage. Just Cordova. Long scrolling lists and unfortunately large DOM even though we have made significant strides to reduce. However we've had FastDOM in for years and I was considering taking it out in consideration of the advancements these past CPL years.

@yellow1912
Copy link

For long scroll you may want to check virtual scroll technic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants