1

In JavaScript, we fire functions in quasi-parallel:

window.onload=function(){
document.getElementById("test").addEventListener('click', function1(), false);
//consider it takes 3 seconds to be completed
document.getElementById("test").addEventListener('click', function2(), false);
}

How we can fire function2() when the function1() has been completely executed?

In jQuery, we can chain a series of functions as (for example):

$(this).fadeIn(3000).fadeOut(2000);

How to make this change of functions in pure JavaScript?

EDIT: In response to a negative comment and vote, I provide this example:

function delay(time, func){
setTimeout(func,time);
}

delay(2000,function(){alert('Function 1');});
delay(1000,function(){alert('Function 2');});

In this example, you'll first see the alert for "Function 2".

7
  • 1
    In your snippet, function2 is executed after function1's execution has ended. What's your point? Commented Jun 30, 2012 at 8:40
  • @MaxArt no it does not. see the edit! Commented Jun 30, 2012 at 8:44
  • 3
    Why are you making a delay function that just calls setTimeout with the parameters reversed..? O_o if you don't want function 2 to execute before function 1, don't set a timeout less than that of function 1. Normally (your first code block) functions execute one after another. Commented Jun 30, 2012 at 8:48
  • @sachleen This is just a simple example to show the issue. Consider the functions are fading in/out as given in the jQuery example. Commented Jun 30, 2012 at 8:51
  • 1
    @Ali Yes, it does. function1 is completed and then function2 is executed. What's executed after function2, is an anonymous function defined in function1 that is executed asynchronously. If you don't understand this, you lack some basic concepts of Javascript. Commented Jun 30, 2012 at 8:52

6 Answers 6

4

If function1 is asynchronous you will have to modify it so that the caller could pass a callback that will be executed once it completes, the same way for example jQuery's ajax method provides callbacks such as success, error, ...:

window.onload = function() {
    function1(function() {
        // the callback is executed once function1 completes so
        // we can now invoke function 2
        function2();
    });
};

which by the way could be written in a little more concise way as:

window.onload = function() {
    function1(function2);
};
Sign up to request clarification or add additional context in comments.

2 Comments

This is a localized remedy. I am looking for a global solution to do for any function, not to create a special function for a case.
I am afraid that you won't find a global solution because it doesn't exist. If you are working with an asynchronous API, this API is obliged to provide the consumer with callbacks. If it doesn't you don't have much choices to achieve this reliably. You could always write some polling mechanisms using setInterval to test whether the first function has completed, but honestly, it's not reliable.
2

I amended the code a bit so it uses JSON and more JQuery-like...

function $c(func){
    var obj;
    if(func=='alert'){
        obj={
            'queue':[],
            'timeout':null,
            'alert':function(timeout,prompt){
                obj.queue.push({timeout:timeout,prompt:prompt});
                if(obj.timeout==null){
                    obj.timeout=setTimeout(obj.do_alert,timeout);
                }
                return obj;
            },
            'do_alert':function(){
                var current=obj.queue.shift();
                alert(current.prompt);
                if(obj.queue.length>0){
                    obj.timeout=setTimeout(obj.do_alert,obj.queue[0].timeout);
                }else{
                    obj.timeout=null;
                }
            },
        };
    }else if(func=='write'){
        obj={
            'queue':[],
            'timeout':null,
            'write':function(timeout,text){
                obj.queue.push({timeout:timeout,text:text});
                if(obj.timeout==null){
                    obj.timeout=setTimeout(obj.do_write,timeout);
                }
                return obj;
            },
            'do_write':function(){
                var current=obj.queue.shift();
                var node=document.createTextNode(current.text);
                document.body.appendChild(node);
                if(obj.queue.length>0){
                    obj.timeout=setTimeout(obj.do_write,obj.queue[0].timeout);
                }else{
                    obj.timeout=null;
                }
            },
        };
    }
    return obj;
}

$c('alert').alert(1000,"This is an alert...").alert(3000,"...sequence.");
$c('write').write(1500,"Writing with...").write(1000," delay.").write(1000," Yay!");

Explanation:
This creates a function $c that returns an object obj. obj depends on the passed argument so it contains different methods for use. Separated calls forms different queue so jobs can be done in both style, in sequence or parallel. Calls to the function returns obj also, so that function calls can be chained together.

1 Comment

That's it. This is exactly what I meant: how to make a queue for functions. I think this is somehow what jQuery does too. Thanks!
1

If events are synchronous, there is the Continuum function to run functions in sequence:

function keyedSequence(key, fn) {
  fn = fn || this;
  key.push({fn:fn});

  return function() {
    for(var i=0, n, full=1; i<key.length; i++) {
      n = key[i];
      if(n.fn == fn) {
        if(!n.called) n.called = 1, n.args = key.slice.call(arguments);
        if(!full) break
      }
      if(!n.called) full = 0
    }

    if(full) for(i=0; i<key.length; i++)
      n = key[i], key[i] = {fn:n.fn}, n.fn.apply(n, n.args);
  }
}
Function.prototype.seq = keyedSequence;

You provide an empty array as the key. Functions keyed with the same key will be grouped together.

window.onload = function() {
  var key = [];
  document.getElementById("test1").addEventListener('click', function1.seq(key), false);
  document.getElementById("test2").addEventListener('click', function2.seq(key), false);
}

Click test2, then click test1 and order of execution is still function1 then function2.

Another way of calling it is:

window.onload = function() {
  var key = [];
  document.getElementById("test1").addEventListener('click', keyedSequence(key, function1), false);
  document.getElementById("test2").addEventListener('click', keyedSequence(key, function2), false);
}

Comments

0

There is no way to tell when every event handler set up by a function has been fired without those event handlers being written in such a way to do so explicitly.

If function 1 says "Do something when X is clicked" or "Do something after 20 seconds" or "Do something when an HTTP response is received", and you want function 2 to run after whichever one of those has happened, then you need to set that up in the "something" level, not the "calling function 1" level.

delay(2000,function(){
    alert('Function 1');
    delay(1000,function(){alert('Function 2');});
});

2 Comments

I gave this example for simplicity. Definitely, both functions work for a single event, as jQuery does. I edited the example to explain the situation.
@Ali - That is the only way to do it (unless there is an actual event handler to bind to for whatever it is you are doing). jQuery just has some helper functions which will do some of that for you in some circumstances.
0

You can use the self-determined function (or "deferred function determination") like this:

var selfDetermine = function() {
    alert("Hi, this is the first time we meet.");
    selfDetermine = function() {
        alert("Hello again!");
    }
}

Comments

0

You can utilize jQuery.when() to defer the execution of one function until another has completed it's execution.

Something like this should work for you:

$.when(delay(2000,function(){alert('Function 1');})).done(delay(1000,function(){alert('Function 2');}));

jQuery documentation on when()

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.