Jump to content


Invalidate() not using updated variable value

Moderator Tag

Recommended Posts

See the attached code pen.


On initialisation, the height and width variables will get updated to reflect the size of the box.

Click play 1, and the box will increase in size to double the size of the width variable. It'll update the variable after the animation completes.

Click play 2, and the box will decrease in size by halving the width variable. Again, it'll update the variable after the animation completes.


Play 1 works as expected.

Play 2 halves the original variable width.


I get that that is expected behaviour, as when the timeline is initialised, it caches the values in the timeline object, but I thought invalidating the timeline was supposed to recheck the values that the variable references?


Am I not understanding what invalidate() does correctly?


And if so, is there a way to force the timeline to use the update variable value?


I'd rather avoid creating the timeline within a function if I can as I'd like to keep things clean, and I'd also really like to understand what invalidate does exactly.



Many thanks!

See the Pen YNGqZV by anon (@anon) on CodePen

Link to comment
Share on other sites

Yeah, I can see why that might be a little confusing, but it has absolutely nothing to do with GSAP - it's just how JavaScript works. It's a logic flow issue. Let me explain...


Try to think through it as if you're the JavaScript runtime. You created both timelines and tween at a particular time, when the width/height variables are certain values. The runtime executes this immediately: 

... width: boxWidth * 2; //evaluates to 50 * 2, or 100. 

It does NOT somehow remember that the number was the result of multiplying some variable that you mutate later. Another example:

var a = 2;
var b = a + 2;
a += 10;
console.log(B); //4, **not** 14!

See what I mean? Just because you changed the value of variable a later on, it doesn't go back and say "hey, the b variable referenced a during its calculation, so now that a changed, we must update b."


All that being said, you can still get the result you're after by using function-based values so that you can force things to be dynamically calculated. Here's a fork:



Note: function-based values were introduced in GSAP 1.19.0, so make sure you're not using an old version. 


Does that help? 

  • Like 3
Link to comment
Share on other sites

Hi Jack,


Thanks a ton for explaining that! Makes a lot of sense now.


So JS assigns the value to the object key, and will only remember a formulae if it's wrapped inside a function?


I'm fairly new to JS objects (but was originally a Java developer, so not new to the OO/dot-notation concept), so it seems I still have a lot to learn.


I'm now wondering if I could extend the GSAP TimelineLite object to have a .live() method, that will wrap all object value's in a return function, so that I don't need to think about this in the future... Although I'm wondering if there'll be a noteworthy performance impact changing something like:

  .to($('.someClass'), 1, {
    x: 2 + 5


  to($('.someClass'), 1, {
    x: function() { return 2 + 5; }

What do you reckon?


Implementing something along the lines of what's described in this super short article: https://davidwalsh.name/javascript-functions


Are there any negative points/things to consider if I'm planning on wrapping ALL object value assignments in a return function?



Oh, and thanks again for the assistance Jack. :D

Link to comment
Share on other sites

Function calls do add overhead, but you're probably not going to notice it unless you're creating 1000s of tweens on every animation frame. JavaScript is fast. Messing with the DOM isn't. I also think the browser optimizes function calls that have less than 500 characters, so don't put comments inside your functions.


If you know Java, you might want to check out the latest version of JavaScript (ES2015/ES6) which has added classes and arrow functions. Arrow functions are like lambda expressions, so this...

tl.to('.someClass', 1, {
  x: function() { return 2 + 5; }

...becomes this.

tl.to('.someClass', 1, {
  x: () => 2 + 5

And that David Walsh article is pretty old (in JavaScript years). There are now built-in ways to create acessors with getters / setters. Check out this demo showing a couple different ways to use them GSAP.

See the Pen 6d42dd35adee8af8ce9c1bcf3f2e6cb2?editors=0010 by osublake (@osublake) on CodePen





  • Like 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.