divHelper11
divHelper11

Reputation: 2208

Looping a JavaScript function

Would somebody mind to explain me what is the difference between these scripts below? The first one found here on Stack Overflow, the second one is my own version that I better understand but is not working. Why doesn't it work by the way?

1.

(function blink() { 
  $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
})();

2.

function blink() { 
  $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
  blink();
}
blink();

Upvotes: 6

Views: 783

Answers (6)

Master DJon
Master DJon

Reputation: 1965

The line $('.blinkMe').fadeOut(500).fadeIn(500, blink); already calls the blink when ending. So calling back blink() is like having twice the function called (and even more on each call). So this call was the problem.

EDIT : But as I just learned today, the timers aren't executed on a different thread in JavaScript. So, the blink() within the blink function takes all the executions frames and the blink callback is never called, but it is still registered to be called. As, I tested by adding a maximum number of iteration that the within blink() could be called.

function blink() { 
  $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
  //blink();
}
blink();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<span class="blinkMe">Blinking</span>

Upvotes: 6

Starfish
Starfish

Reputation: 3574

The first example is an Immediately-Invoked Function Expression (IIFE). It is a function which immediately executes itself after creation. IIFE is a common JavaScript design pattern used by most popular libraries (jQuery, Backbone.js, Modernizr, etc) to place all library code inside of a local scope.

In ES6 this can be rewritten using the Arrow function if you want the .blinkMe to blink just once:

(() => $('.blinkMe').fadeOut(500).fadeIn(500))();

You can chain as many fadeIn and fadeOut functions as you want of course. If you want it to loop infinitely I'd suggest the IIFE way.

More info about IIFE here.


About your second example. You're calling the function inside your own function (also known as recursive loop). In your case this creates an infinite loop, that's why it doesn't work. Remove the blink(); inside the function and it will work:

function blink() { 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
}
blink();

Besides with javascript you can also solve this issue with CCS3 animations. CSS3 animations run in a separate thread. This is a solution without jQuery:

(function blink() {
  document.getElementsByClassName('blinkMe')[0].className += ' blinkActive';
})();

// Arrow function:
//(() => document.getElementsByClassName('blinkMe')[0].className += ' blinkActive')();
.blinkMe {
  width: 80px;
  height: 80px;
  background: deepskyblue;
}
.blinkActive {
  -webkit-animation: blink 1s infinite;
  animation: blink 1s infinite;
}
@-webkit-keyframes blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}
@keyframes blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}
<div class="blinkMe"></div>

I don't know how many elements you want to blink on your page, if it's just one element you can use ids instead of classes. Keep in mind that the @keyframes rule is not supported in IE9 or earlier versions and Opera Mini: Link.

Upvotes: 11

Alexander O&#39;Mara
Alexander O&#39;Mara

Reputation: 60507

In this snippet, a named function is created, then immediately executed once in an Immediately-Invoked Function Expression. The function name is only available to itself, so it can again be called within the closure of the function body, in this case as a callback to the fadeIn function.

(function blink() { 
  $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
})();


In this snippet, a named function is created, and called. Additionally, the function again calls itself, which will create an infinite recursion, which is why it fails. Unlike the last snippet, blink will also be available outside the function closure itself.

function blink() { 
  $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
  blink();
}
blink();

Removing the blink() call inside the function itself as follows will make it function nearly identical, except for the different in blink scope.

function blink() { 
  $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
}
blink();

Upvotes: 6

Nishanth Shaan
Nishanth Shaan

Reputation: 1472

Your function works, but the Navigator blocks it because of too much recursion. because you are callling blink() just after you fadeIn just try,

function blink() { 
  $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
  //remove this call which causes too many recursions 
  //blink();
 }
//then call the method
 blink();

Upvotes: 2

Juanjo Salvador
Juanjo Salvador

Reputation: 1093

This is a recursive function (animation).

According to the jQuery docs, fadeIn() takes two arguments: duration (in ms) and complete. The second argument is a function that is called once the animation is complete. It can be itself, or another function.

In the second function you are calling blink() again and again... but the second and the third never comming. Best way is the first.

Upvotes: 2

Neil S
Neil S

Reputation: 2304

The first is a IIFE . That is, the function is immediately invoked (executed) after it is declared. It is not attached to the global window object and so does not pollute it.

The second function is exponentially recursive. Every time it is run, it calls itself twice more, once as a callback to the fadeIn jquery method, and once more in the function body.

Upvotes: 7

Related Questions