1

I've got some functions all set up. One's a typing effect, one is for paragraphs, other for adding " " and one for a blinking cursor like in the terminal. All these change the innerHTML of a div.

When the page loads the function Start() has about 10 functions inside it that makes up a sequence of what should happen: Text is written, cursor starts blinking, paragraph, text written again, etc, etc.

The thing is, they all execute at the same time unless I use setTimeout() for each one inside the Start() function. And that's kind of messed up given that I have to define a start time for each one of the functions.

EDIT: No JQuery here. Just javascript. This is my whole JS file:

ctrl = 0;
y=0;
block = 0;
test = "";
first_time = 1;

function typing(id, sentence){

        var index=0;
        var intObject= setInterval(function() {
               document.getElementById(id).innerHTML+=sentence[index]; 
               index++;
               if(index==sentence.length){
                     clearInterval(intObject);
                }
            }, 100);
}


function paragraph(x){
    while(x>0){
        document.getElementById("container").innerHTML+="<br>";
        x--;
    }
}

function advance(x){
    while(x>0){
        document.getElementById("container").innerHTML+="&nbsp;";
        x--;
    }
}


function blink(y){
    if(first_time == 1){ctrl = y; first_time=0;}
    if(ctrl!=0){
        if(block=='0'){
        test = document.getElementById("container").innerHTML;
            document.getElementById("container").innerHTML+="\u258B";
            block=1;
        }
        else if(block=='1'){
            document.getElementById("container").innerHTML=test;
            block=0;
        }
        ctrl--;
        setTimeout("blink(y);", 300);
    }
    if(ctrl==0){first_time=1;}
}


function start(){
    typing('container','Subject Name:');
    setTimeout("blink('4');",1700);
    setTimeout("typing('container',' Carlos Miguel Fernando');",2800);
    setTimeout("blink('6');",5600);
    setTimeout("paragraph('1');",7200);
    setTimeout("blink('8');",7400);
    setTimeout("typing('container','Age: 21');",9500);
    setTimeout("blink('4');",10800);
    setTimeout("paragraph('1');",12800);
    setTimeout("blink('4');",13200);
    setTimeout("typing('container','Location: Povoa de Varzim, Portugal');",14500);
    setTimeout("blink('14');",19000);
    setTimeout(function(){document.getElementById("more").style.display="block";}, 23000);
    setTimeout("typing('more','Find Out More');",24000);
}
cmf
  • 435
  • 1
  • 9
  • 21
  • 3
    Besides the fact that it's horrible to pass strings to the timeout, the solution heavily depends on your functions. They seem to be asynchronous, so you have to work with callbacks or promises. Maybe an animation queue is what you need. If you don't mind, you can have a look at jQuery where you have all these mechanics already implemented. – Christoph Dec 05 '13 at 09:39
  • 3
    The problem is more complicated than it seems. I suggest you learn about callbacks and asynchronous programming in JavaScript. Look for these terms: "higher-order functions", "promises", "continuations". That should get you started. – elclanrs Dec 05 '13 at 09:39
  • Just edited it and added my whole javascript file. Maybe that's somewhat useful. I'll get some info on Asynchronous functions and Callbacks guys, thanks! – cmf Dec 05 '13 at 09:45
  • http://stackoverflow.com/questions/899102/how-do-i-store-javascript-functions-in-a-queue-for-them-to-be-executed-eventuall and http://stackoverflow.com/questions/17528749/semaphore-like-queue-in-javascript/17528961#17528961 – Satpal Dec 05 '13 at 09:46

2 Answers2

3

First you need a way to find out when a function has ended. The ideal mechanism is called a promise. There's a good implementation in jQuery. Suppose in your list of activities you wanted an artificial delay:

blink(4);
sleep(1000);   // wait 1 second
blink(4);

Implement that like this:

var sleep = function(ms) {
    var result = $.Deferred();
    setTimeout(result.resolve, ms);
    return result.promise();
};

i.e. create a $.Deferred, and return its promise(), but in between, start some activity that will complete at a later time. When it does, call resolve() (here I just get setTimeout to call it directly). You can pass a value to resolve to be the logical "return value" of your function. Also you can instead call reject which is logically like throwing an exception.

Once you have a set of building block functions that return promises you can do this:

typing('container','Subject Name:').then(function() {
   return blink('4');
}).then(function() {
   return typing('container',' Test');
}).then(function() {
   return blink('4');
}).then(function() {
   // and so on
});

UPDATE:

Click here to see a quick mock-up in jsbin.

Daniel Earwicker
  • 114,894
  • 38
  • 205
  • 284
  • +1 because .. promises need more exposure. (However, it should be noted that jQuery 1.8+ should probably be used for proper `then` support .. or maybe that was another broken-promise issue. There is also [Q](https://github.com/kriskowal/q) and whatnot.) – user2864740 Dec 05 '13 at 09:51
  • NB. I believe Q and jQuery differ over what should happen if `resolve` is called a second time on the same promise (Q throws, jQuery ignores). – Daniel Earwicker Dec 05 '13 at 10:01
  • Getting an "Uncaught TypeError: Cannot call method 'then' of undefined" error with that, still it solves my problem once I get it working. Thanks! – cmf Dec 05 '13 at 10:04
  • @DanielEarwicker Interesting bit of knowledge - I've never run into the case myself (yet). – user2864740 Dec 05 '13 at 10:05
  • @user2864740 - probably a good sign! It would usually indicate a bug in your logic. So it would be better if jQuery would throw, to help us find such bugs. – Daniel Earwicker Dec 05 '13 at 10:06
  • @CarlosMiguelFernando - be sure to check out the jsbin I linked to as it is a working example. – Daniel Earwicker Dec 05 '13 at 10:07
  • @DanielEarwicker, I did, and I added it. Now I've got a "Uncaught ReferenceError: $ is not defined " although I've added the to my HTML – cmf Dec 05 '13 at 10:26
  • 1
    @CarlosMiguelFernando - it sounds like you need to ask new questions (or find existing ones) on SO, something like "How do I reference jQuery from my HTML/JavaScript application?" – Daniel Earwicker Dec 05 '13 at 10:44
0

check below code

function blink(id)
{
    //Do something
    alert(id);

    if(id == 2)
    {
        //call typing with text
        blink(4);
    }
    if(id == 4)
    {
        //call typing with text
        blink(6);
    }
    if(id == 6)
    {
        //call typing with text
        blink(8);
    }
    if(id == 8)
    {
        //Complete
    }
}

And call blink(2); it will call blink function one after another.

Bhavesh Parekh
  • 212
  • 2
  • 11
  • 1
    The issue is that "call typing with text" is asynchronous - it returns immediately but activity continues. If `blink` just calls itself immediately then all the steps will run with no delay. This will be no different to the OP's original non-working code where they just called the functions sequentially. – Daniel Earwicker Dec 05 '13 at 10:05