TheFieryTortoise
TheFieryTortoise

Reputation: 55

setTimeout inside for loop doesn't behave as expected

I am creating a function that when you press a button it pops up a random symbol one at a time with a delay inbetween and then changes to a readable word once all symbols load up. I can't get the delay to work. I havent added the part that will turn the symbols into a readable word yet because I cant finish this.

//Brute Force
function work() {
    setTimeout(function() {
        var $rand = Math.ceil(Math.random() * 10);
        $('#txtBrute').append($sym[$rand]);
    },1000);
};
var i = 1;
var $sym = [1,9,"%","$",")",">","@","?","-","|",7];
$('#btnBrute').click(function() {
    var $pass = "password123";
    $('#txtBrute').html("");
    for(i = 1; i <= $pass.length; i++) {
        work();
    };
});

Upvotes: 1

Views: 70

Answers (2)

ETHproductions
ETHproductions

Reputation: 499

setTimeout() doesn't affect when the rest of the code is run, so the loop launches all timeouts at once. As a result, they are all called at once, after 1000 milliseconds. Rory's answer suggests making work() recursive; another way to solve this, perhaps easier to implement but not as usable, would to pass a delay amount into work():

function work(delay) {
    setTimeout(function() {
        var $rand = Math.ceil(Math.random() * 10);
        $('#txtBrute').append($sym[$rand]);
    }, delay);
};

var i = 1;
var $sym = [1,9,"%","$",")",">","@","?","-","|",7];

$('#btnBrute').click(function() {
    var $pass = "password123";
    $('#txtBrute').html("");
    for(i = 1; i <= $pass.length; i++) {
        work(i * 1000);
    };
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btnBrute">Go</button>
<pre id="txtBrute"></pre>

Upvotes: 2

Rory McCrossan
Rory McCrossan

Reputation: 337560

The issue is because you're calling work() in a loop, so all the timers execute immediately.

Instead of this you could make work() recursive. You can use the length of the password as a decremental value over each recursion. Try this:

var timeout;
var $sym = [1, 9, "%", "$", ")", ">", "@", "?", "-", "|", 7];

function work(length) {
  timeout = setTimeout(function() {
    var $rand = Math.ceil(Math.random() * 10);
    $('#txtBrute').append($sym[$rand]);
    --length != 0 && work(length);
  }, 1000);
};

$('#btnBrute').click(function() {
  clearTimeout(timeout);
  var pass = "password123";
  $('#txtBrute').html("");
  work(pass.length);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btnBrute">Go</button>
<div id="txtBrute"></div>

Also note that I added a clearTimeout() call, should someone decide to keep pressing the button while the recursive loop is still running.

Upvotes: 3

Related Questions