Jump to content
Search Community

instanceof Array pitfalls?

edbras test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

I noticed the Greensock is using "instanceof Array" conditions in if statements.

This has some known problems like explained in this link.

 

Because of this I can't use some methods in which I specify an array of tweens/timelines in which greensock does a check on this through "instanceof Array" such that it shows an error as it detects it's now an array, where as it sure is an array.

It's because I am using the greensock lib from within a frame (through Google GWT).

 

Any workarounds?

Idea's on this "instanceof Array"? will this be changed in the comming release for example?

Thanks,

- Ed 

Link to comment
Share on other sites

Hi.

 

In order to properly address this issue it would be most helpful if you could provide an example of the problem. 

 

By Google GWT, I'm assuming you mean Google Web Designer, but from what I know that just generates fairly basic html and css so posting those files or converting them to a codepen or jsfiddle example should be fairly straight-forward. Not really sure how GWD could be doing something that makes an arrray not an an array.

Again, having a simple example that clearly illustrates the issue will help us greatly in deciding what may or may not need to be done.

 

Thanks.

  • Like 1
Link to comment
Share on other sites

Let me give you more details:

 

The "instanceof Array" has nothing to do with GWT, it's just that I am trying to use the lib through GWT, such that I encounter the problem. But I will also encounter this problem when calling the lib through html frame as explained in the link provided in previous post: linke.

It also has nothing to do with GWT designer, I don't even use it. I like it the old fashion way as I have build my own gwt tools/components in the mean time.

 

Example: the GSAP method I call (more methods have the same problem):

 TimelineLite.add(values, position, align, stagger); 

javadoc: linke

As values: an array of tweens, example:

tl.add([tween1, tween2, tween3], "myLabel+=2");

Calling this method from a frame, results in the following error:

throw("Cannot add " + value + " into the timeline; it is not a tween, timeline, function, or string."); // line 103 in TweenMax uncompressed.

It's because of this line of code in TweenMax uncompressed:

if ((child = value[i]) instanceof Array) { // (line 48 TweenMax uncompressed).

Additional explanation why this fails, see this post in the GWT forum: linke

 

If you need more details, let me know. 

Link to comment
Share on other sites

Interesting - well, the problem with the solution you linked to is that it's literally like 20x slower than the regular instanceof check, and we've tried VERY hard to optimize the snot out of GSAP, so it's painful to alter the [fast] code we've got in place, especially since you're the first person who has stumbled across the frame thing. However, as GSAP gets more and more popular (and our goal is to be the standard for scripted animation on the web), I can definitely see others stumbling across that as well. So I've come up with a hybrid solution that should keep things fast in 95%+ of the cases and only slow down a bit when you're in environments like what you described with multiple frames. And the slowdown only affects when the tween instantiates anyway (it's not like the whole engine would slow down during all animations).

 

Would you mind trying the attached files to see if they work well for you? 

GSAP_1.11.0_rc7.zip

  • Like 4
Link to comment
Share on other sites

Hi,

Your are fast... just like GSAP ...

I agree what you are saying.

The "main flow"  must be super fast, but a fall back in case it's not an Array, as an extra check is nice. What I understand, that what you did.

And yes, I expect more people using GSAP as well. I build a wrapper such that it can be used in a friendly/efficient way from GWT directly. I am planning to drop it as an open source such that others can use it. I just have to find a moment to do this  (isolate the dependencies) :(. Wrapping it cost a bit more time then I expected, because of the strongly typed behavior of Java, and not supporting closure (yet)..

 

Just tested, it and it's almost solved. Its recognized as Array, so the add method with array works.

However, when adding a function (instead of a tween), I do get the following error:

I get this JS error in Firebug:

TypeError: v is undefined
...instanceof Array) || (v.push && _isArray(v))) if (v.join("").indexOf("{self}") !...
166 TweenMax.js (line 6109)

What I do:

Add a tween, which works.

Add a function to the timeline that doesn't work because of the above error.

The error occurs in the following code:

v = this.vars[p];
if (_reservedProps[p]) {
if ((v instanceof Array) || (v.push && _isArray(v))) if (v.join("").indexOf("{self}") !== -1) {
this.vars[p] = v = this._swapSelfInParams(v, this);
}

And when the error occurs, the value of p is "onCompleteParams".

The value of this.vars: linke

Any idea?

Link to comment
Share on other sites

Yes, solved, works great, no errors, just nice animations :)

 

BTW: I noticed there isn't a method "isTweening()" on a tween instance. There does exists a static method, but I have a tween instance and want to check if it's running.

 

I though about performing "tween.progress() > 0 &&  tween.progress() < 1" to check if it's running.

Is that the way to go?

Link to comment
Share on other sites

Hi

What you could try is check if the instance is active. If you check the progress like that, a paused tween/timeline will return as a running one if it has advanced any amount of time before being paused.

You can check the state with the following code:

var tn = TweenMax.to(element, time, {vars}),
    tweenState = tn._active;//returns a boolean

You can see it here:

See the Pen Cnbwd by rhernando (@rhernando) on CodePen

Best
Rodrigo.

  • Like 1
Link to comment
Share on other sites

Yes, although Rodrigo's suggestion should work, variables preceded with _underscore are  private and intended for use within the engine. So, it might work fine for your immediate use case, but just as a general rule-of-thumb you might want to be cautious about how heavily you rely on these types of features. 

 

The good news is there is a public isActive() method in the upcoming v 1.11.0 release which you can snag an early preview of here: http://forums.greensock.com/topic/8339-draggable-on-windows-8-touch/#entry32419

 

 

isActive() is part of all animation classes (TweenLite, TweenMax, TimelineLite and TimelineMax)

 

isActive() will return true on an animation if:

  • The virtual playhead is actively moving across it (if the parent timeline's playhead is positioned BEFORE the tween's start or AFTER its end, it wouldn't be active of course)
  • It isn't paused
  • None of its ancestor timelines are paused
  • It hasn't been killed

 

Or for most cases the following conditional (similar to yours) should work well

if (!tween.paused() && tween.time() > 0 && tween.time() < tween.totalDuration()) {

}
  • Like 2
Link to comment
Share on other sites

Here it is:

tw = Tweening.from(element, 2, {autoAlpha: 1};
tw.isActive(); // undefined/null
...
// after a 1s delay, when the tween is still running.
tw.isActive(); // undefined/null

Notes:

  • The animation runs well.
  • In my java code I receive a null, as such I am not sure it's undefined or null in JS, as both are mapped to Java null.

If you want me to debug the JS method, let me know?

Link to comment
Share on other sites

Your partial code has some errors (Tweening.from) so its difficult to accurately assess where the real issue is.

 

I created a basic codepen example which shows 3 isActive() states of a tween:

 

As soon as it is created and paused : false

While it is running  : true

After it completes: false

 

 

var state = document.getElementById("state");
var t = TweenLite.to("#logo", 1, {left:632, paused:true, onComplete:getActive});




function getActive() {
   state.innerHTML = t.isActive();
}


//get active state on load
getActive(); // returns false


//start tween after 1 second
TweenLite.delayedCall(1, t.play, [], t)


//get active state when tween starts
TweenLite.delayedCall(1, getActive) //returns true


//final getActive() is called via tween's onComplete.
//returns false

http://codepen.io/GreenSock/pen/LEFxH

 

Feel free to fork that pen in a way that clearly illustrates isActive() returning undefined or null. 

  • Like 1
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.
×
×
  • Create New...