2

How to use jquery to create infinite animation, BUT NOT using recursion way?

The recursion solution I found: jQuery .animate() callback infinite loop

The problem of using recursion is: while animating, the browser tab of currrent page will take MORE and MORE memory.

Community
  • 1
  • 1
Littlee
  • 3,791
  • 6
  • 29
  • 61
  • 2
    did you actually verify that it takes up more and more memory – Foon Mar 07 '15 at 13:30
  • 1
    Please show the code you are using. – charlietfl Mar 07 '15 at 13:31
  • 2
    Why not using CSS animation? – A. Wolff Mar 07 '15 at 13:33
  • @Foon I opened my page in chrome an using chrome task manager to check it (shift + esc), the memory of that page keep increasing per sec. – Littlee Mar 07 '15 at 13:53
  • @charlietfl I was using the same pattern following: http://stackoverflow.com/questions/6461945/jquery-animate-callback-infinite-loop – Littlee Mar 07 '15 at 13:55
  • @A.Wolff Nice Suggestion. I knew CSS animation, just looking for a jquery way. Curiosity ^_^ – Littlee Mar 07 '15 at 13:59
  • @Littlee we shouldn't have to go to other links to see the code you are using – charlietfl Mar 07 '15 at 14:02
  • The code used, from the linked question, may look recursive but it is not actually *stack-based* recursive. See my answer below. If you have a memory leak it will be down to something else going on. Don't be fooled into changing a very simple animation pattern into something more complicated. – iCollect.it Ltd Apr 15 '15 at 14:09

2 Answers2

3

You have actually made a mistake in assuming that the code is "recursive". It is not recursive. Your comment that "the browser tab of current page will take MORE and MORE memory." is not because of any recursion in that code. If you have a memory leak per second (as per your comments), then the problem lays elsewhere.

The instances of the code actually run sequentially and not via nested stack calls (i.e. linear and not recursive).

Using the most basic example you linked to:

function start() {
    $('#element').animate({}, 5000, 'linear', start);
}
start();

here is what actually happens:

  • A function called start is defined and then called once
  • Inside start, an animation operation is started, then start immediately exits!
  • The animate just adds information to a single animation queue for the element, then returns.
  • The animation queue is processed step by step by a separate process (single timer etc).
  • When the queued entry has met its expected end state, it calls the callback - The global start function stored in the queued entry.
  • That simple adds another entry on the animation queue and exits.

Basically the code looks recursive, but as the operations are async, via a queue, it is not recursive. I don't know if there is an official name for these, so I just call them chained callbacks.

iCollect.it Ltd
  • 92,391
  • 25
  • 181
  • 202
  • [I've heard](http://stackoverflow.com/a/29456618/1048572) the term "pseudo-recursion" for it. Basically, it *is* recursion, but a call-stack optimised one (like tail calls). – Bergi Apr 15 '15 at 14:00
  • @Bergi: Call me old-school, but that does not meet my definition of recursion (code actually calling itself). In this instance a separate process is working through the queue. – iCollect.it Ltd Apr 15 '15 at 14:01
  • Oh, I'm coming from a functional programming background, where you don't care about "calls" at all and more about structure. It definitely is a recursive approach :-) – Bergi Apr 15 '15 at 14:05
  • @Bergi: Fair enough. His question implied concerns about "growing memory usage", which implied stack-based recursion, rather than the problem being recursive in nature, hence my answer. – iCollect.it Ltd Apr 15 '15 at 14:06
  • @TrueBlueAussie regardless of what theories you have, the code you provide here causes the memory usage to quickly increase for that tab. My solution above is a little better, but still eats memory. – Tech Savant Apr 18 '15 at 18:55
  • @NotoriousPet0: the code was for description only from the other answer and not intended as a code solution at all. As I stated any memory leak will be down to other issues and it is those that need to be addressed. – iCollect.it Ltd Apr 18 '15 at 19:02
  • Yeah but your defending that code saying its not going to cause a problem, and it does. so you are wrong. its ok some people cant admit that and will make excuses til time ends. I tested this on bare code base, just this an djquery. and on js fiddle, both have same speed of memory increase. – Tech Savant Apr 18 '15 at 19:09
  • @NotoriousPet0: feel free to provide the test code to which you refer. I do not need to defend this answer as it is technically correct. Any memory issues are a side-effect of other issues (to be determined) and not the assumed stack-based "recursion". That is my one and only point: further investigation is required to identify the actual problem. – iCollect.it Ltd Apr 18 '15 at 19:32
  • No, it's not. You can check the other tabs and see there is no leak. You can run one tab with the code, and one tab without the code. If memory is leaking, you can be sure it's the code. Are you even a developer? This is basic. See my answer for test code. – Tech Savant Apr 18 '15 at 19:36
  • @Notorious Pet0: While you provide alternatives, your answer does not explain why the original code is leaking. Sorry your answer was accepted but not up-voted, but I really do not have more time to waste when I was purely explaining the misunderstanding the OP had about recursion in this instance. FYI SO profiles have a little link to give further information about those you wish to insult. Probably worth a check to avoid further embarrassment :) – iCollect.it Ltd Apr 19 '15 at 17:59
0

UPDATED WITH TEST RESULTS

Conclusion... All methods burn up the same amount of memory and it eventually gets released, doesn't keep building forever so not really an issue.

Example 1

This is the code the OP originally had a problem with memory usage increasing in Chrome.

(function($){
    $(function(){  //document.ready

        function start() {
                $('#animate').animate({'margin-left':'150px'}, 1000, function () {
                    $(this).animate({'margin-left':'50px'}, 1000, 'linear', start);                
                });
        }
        start();

    });
})(jQuery);

Example 2

Current solution including a callback as requested by Bergi to avoid potential "drifting" in setinterval.

(function($){

    $(function(){  //document.ready

    });

    (function customSwipe(element) {
        element
            .animate({"margin-left" : "150px"}, 1000)
            .animate({"margin-left" : "50px"}, 1000, function(){
                setTimeout(function(){
                    customSwipe(element);
                }, 2000);
            });
    })($('#animate'));

})(jQuery);

Example 3

Original Answer I gave, using setInterval()

(function($){
    $(function(){  //document.ready

            setInterval(function(){
                    $("#animate").animate({'margin-left':'150px'},1000);
                    $("#animate").animate({'margin-left':'50px'},1000);
            },2000); 

    });
})(jQuery);

Skeleton w/ Jquery

Empty page w/ only the #animate element

(function($){
    $(function(){  //document.ready



    });
})(jQuery);

DATA AFTER TAB OPEN FOR 10 MINUTES

CODE            STARTING    ENDED
Example 1       14.300k     19.996k
Example 2       14.300k     20.020k
Example 3       14.300k     20.344k
Skeleton w/ jQuery  14.300k     15.868k

Interesting that the code that did nothing still increased usage slightly. These values go up and down as memory is used and released. Another thing would be to use the "purge memory" button in task manager to see how much of that used memory is garbage waiting to be collected.

DATA AFTER 25 MINUTES

Example 1       14.300k     18.640k
Example 2       14.300k     18.724k
Example 3       14.300k     18.876k
Skeleton w/ jQuery  14.300k     15.868k

Conclusion... All methods burn up the same amount of memory and it eventually gets released, doesn't keep building forever so not really an issue.

So just using the most solid, sound code would be the best option, Example 2 would be my choice.

UPDATED USING CALLBACK

Have you tried using setTimeout with $.animate()?

(function($){
    (function customSwipe(element) {
        element
            .animate({'margin-left':'150px'}, 1000)
            .animate({'margin-left':'50px'}, 1000, function(){
                setTimeout(function(){
                    customSwipe(element);
                }, 2000);
            });
    })($('#animate'));

    $(function(){  //document.ready


    });

})(jQuery);

Remove the setTimeout() if you don't need it to delay between animations.

JSFIDDLE of the above code working...

You might also want to look into this for more intricate animations.

http://api.jquery.com/jquery.fx.interval/

Conclusion... All methods burn up the same amount of memory and it eventually gets released, doesn't keep building forever so not really an issue.

What you are seeing in the Chrome TM is every time it fires the animation, that much memory is requested and the OS "commits" that memory to chrome for the operation. Once the operation is completed, the memory is still committed. At some point Chromes garbage collector comes along and releases that memory and your usage stats will drop back down. So you will see the memory going up and down if you watch it long enough.

You can put --purge-memory-button at the end of your Chrome command line to have a Purge Memory button available in Chrome TM. This might help you to see how much memory is actually waiting to be released.

Hope this answer helps you and maybe some others.

Tech Savant
  • 3,686
  • 1
  • 19
  • 39
  • 2
    this is not really a useful answer. `setInterval` may drift, and when it does get a bit faster than the actual animation you really start filling up memory. To know when the animation has finished, use callbacks, that's what they are for. – Bergi Apr 15 '15 at 13:57
  • @bergi do I really deserve a downvote for that? I didn't get an upvote from the OP in the first place. Plus OP marked it correct. Meaning it worked for them, so the "*Possibility*" of drifting, which is remote, doesn't affect his implementation. Please remove downvote. Thanks. – Tech Savant Apr 18 '15 at 18:17
  • If you went around downvoting everyone who had a solution with an obscure possiblity of some rare failure happening, then you'd be downvoting all day, but hey, maybe that's what you do. I personally have better things to do than hate on people trying to help others. – Tech Savant Apr 18 '15 at 18:18
  • Yes, I think it deserves a downvote because I consider it a bad practise (And it's not only drifting, but also readability and maintainability, what if someone changes `1000` to `1500` but misses to adjust `2000`?). It doesn't matter whether OP upvoted or not, or whether he accepted it. I'm not hating around, and my votes are not personal. It's just when I come across a good answer, I upvote it, and when I come across a bad answer I downvote and comment what is wrong/could be improved from my pov. – Bergi Apr 18 '15 at 18:21
  • @Littlee I updated this answer with a better solution. – Tech Savant Apr 18 '15 at 18:32
  • Thanks, yes. Though the `setTimeout` isn't really needed any more for what OP wanted to do. – Bergi Apr 18 '15 at 18:33
  • @bergi, he did ask for one not using recursion, which is probably why i didn't use the callback. Do you know if this will keep increasing used memory in the browser tab (as OP describes) the way I have set it up now ? – Tech Savant Apr 18 '15 at 18:36
  • Uh, `setTimeout` still has a callback… And passing a callback directly to `animate` is recursive neither, see TrueBlueAussie's excellent answer. – Bergi Apr 18 '15 at 18:38
  • @bergi, i meant on the code you didn't like. which is probably still the best solution for the OP. The code above continues to increase memory usage in chrome task manager. – Tech Savant Apr 18 '15 at 18:41