0

If I write the html:

<script  src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<h1 id="message">
</h1>

and the JS:

messages = ["Here", "are", "some", "messages."]

$(function() {

  for (var i = 0; i < messages.length; i++) {
    $('#message').html(messages[i]).delay(1000);
  }

});

and load the page, I expect to see each string in the array show up with a delay in between. However, all I see is "messages." appear. It seems that the for loop iterates immediately through each value in the array before performing any delay.

I have seen another method for getting the desired visual result (How can I change text after time using jQuery?), but I would like to know why the earlier method does not work. What is going on when this code is executed?

2
  • delay() is asynchronous but the loop is not, so the loop is finishing before the delay and showing you the last element in the array. You need to use a callback function Commented Aug 8, 2016 at 21:58
  • The reason for 'messages' appearing is because it is the last item when the loop finishes iterating over the object. You need to create another variable outside the loop to save the whole thing. Commented Aug 8, 2016 at 22:08

4 Answers 4

2

This is how i would delay my message changing.

function delayLoop(delay, messages) {
  var time = 100;

  $(messages).each(function(k, $this) {
      setTimeout(function()
      {
          $("#message").html($this); 
      }, time)
      time += delay;
  });
}
delayLoop(1000, ["Here", "are", "some", "messages."]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="message">
</div>

All I did was for each message delay by an additional delay time. It works in async mode so its not ui blocking and the messages will display a second after one another.

EDIT:

Removed the .delay from the .html it is redundant.

Sign up to request clarification or add additional context in comments.

4 Comments

It's unnecessary to use both setTimeout and delay, as both are already async. You can simply do something like $(messages).each(function(i, message) { setTimeout(function() { $('#message').html(message); }, delay * i); });
Thank you I didn't notice I did that, I actually just copy and pasted his message function because there was no point to re-write the entire thing but its fixed now, thank you.
You're also passing this to the html call, even though this is undefined within the setTimeout callback.
yeah I know, fixed. Didn't really expect it to run I dont like giving someone an answer I believe they need to learn so if you point them in the right direction...... Anyways above is fixed up you can run it.
1

Note that jQuery's delay is specifically for effects; methods like html do not use the effects queue and are therefore not affected by delay.

This is a problem better solved with JavaScript's native setTimeout function. There are many ways to do this; in fact, you don't even need jQuery!

let messages = ["Here", "are", "some", "messages."];
let delay = 1000;
let header = document.getElementById("message");

messages.forEach(function(message, i) {
  setTimeout(function() {
    header.innerText = message;
  }, delay * i);
});
<h1 id="message" />

Comments

0

You would need something along the lines of

$(function() {
  for (var i = 0; i < messages.length) {
    var done=false;
    $('#message').html(messages[i]).delay(1000).queue(function(){
     done=true;
     $(this).dequeue();
    });
     if(done==true){ 
      i++;
     }
   }
});

1 Comment

Upon looking at JQluv's answer it is a lot more efficient than mine. Go ahead and use his.
0

Thank you for the answers and comments--very helpful.

I also found this post helpful: Node.js synchronous loop, and from it wrote this (which also works):

function changeText() {
    var msg = messages.shift();
  $('#message').html(msg).show(0).delay(1000).hide(0, function() {
    if (messages.length > 0) {
        changeText();
    }
  });
}

(I used .show and .hide because without them only one of the array values appeared. I'm not sure why that is, but that's a question for another time.)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.