ton1
ton1

Reputation: 7628

How to set function execute order to using callback function in JavaScript?

I want to handle functions execute order to using callbacks. Actually I'm learning Node.js. Because of its async, It's difficult to me to handle process. Anyway, There are 3 function that has callback,

function first(callback){
    console.log("First");
    callback;
}

function second(callback){
    console.log("Second");
    callback;
}


function third(callback){
    console.log("Third");
}

// Let's run it!

first(second(third));

// result 

Second
First

I don't understand why the result is. I expected below:

First
Second
Third

What's problem? How could I do it correctly? In Node.js, Do people usually handle functions excute order by using callbacks? that is little complex I think. Isn't it?

Upvotes: 5

Views: 7204

Answers (5)

aggregate1166877
aggregate1166877

Reputation: 3150

If for whatever reason you can't / don't want to switch to promises, the below will work.

// -------------------------------------------------------------- //

function f1(callback) {
  setTimeout(() => {
    console.log('f1 complete');
    callback(null);
  }, 500);
}

const f2 = (callback) => {
  setTimeout(() => {
    console.log('f2 complete');
    callback(null);
  }, 300);
};

// -------------------------------------------------------------- //

class RunInOrder {
  constructor(functionArray = [], onComplete = () => {}) {
    this._index = 0;
    this._functionArray = functionArray;
    this._onComplete = onComplete;
    this._runNext();
  }

  _runNext() {
    if (this._index >= this._functionArray.length) {
      return this._onComplete();
    }

    const index = this._index++;
    const fn = this._functionArray[index];
    fn((error) => {
      error && console.error(`[f${index}]`, error);
      this._runNext();
    });
  }
}

// -------------------------------------------------------------- //

new RunInOrder(
  [ f1, f2 ],
  () => console.log('All done.'),
);
// ^^ the above outputs:
// f1 complete
// f2 complete
// All done.

Upvotes: 0

laggingreflex
laggingreflex

Reputation: 34627

As explained in other answers,

first(second(third));

this doesn't do what you think it does.

I think what you actually meant to do was this:

first(function(){
    second(function(){
        third(function(){
            // ...
        });
    });
});

In ES6 (Node 4+) syntax it'll be:

first(() => second(() => third()));

But what I prefer is an approach that uses Promises

function first(){
    return new Promise(function(resolve, reject){
        console.log("First");
        resolve();
    });
}

function second(){
    return new Promise(function(resolve, reject){
        console.log("Second");
        resolve();
    });
}

function third(){
    return new Promise(function(resolve, reject){
        console.log("Third");
        resolve();
    });
}

This gets rid of callbacks altogether, and makes more sense of the actual control flow:

first()
.then(second)
.then(third);

checkout this article on promises

And with the ES7 syntax (babel/typescript) it simply becomes:

async function first(){
    console.log("First");
}
// async function second...
// async function third...

await first();
await second();
await third();

checkout this article on async/await

Upvotes: 4

Jacques
Jacques

Reputation: 3774

As kajyr said, if an argument in a function call has the () (which tells the function to execute), it will execute before the other function is actually called.

To see this behavior, you can step through the script using 'step in' in your javascript console. Treehouse did a decent post on using the js console.

And here is a good explanation on stepping over, into, etc.

I tweaked your code a bit, not sure if this will work for you, but this will give you the proper order. I just make first accept two callbacks and called them in order.

Also, you need the () after the var name to execute the methods. IE: callback();

function first(callback, cb){
    console.log("First");
    callback();
    cb();
}

function second(callback){
    console.log("Second");
}


function third(callback){
    console.log("Third");
}

// Let's run it!

first(second, third);

Again, kajyr has a correct answer, I'm just giving another solution, and pointing you in the direction you need to see how it works on your own.

Upvotes: 1

Carlo
Carlo

Reputation: 2112

Let's say you have 2 functions, f and g

When you call f(g())

g() is evaluated first in order to provide the correct arguments for f()

so if you want to have f() executed first, and then the result passed to g as a parameter, you have to inverse the flow.

g(f())

Upvotes: 3

Sirko
Sirko

Reputation: 74046

Do don't pass the callback link, but the result of the execution of second(). Your code could be written as:

var a = second(third);
first( a );

This should make it clearer, what happens: You first execute second() and pass the result (which is undefined) as a "callback" to first().


Besides, there are a few syntax errors in this code, it probably should read like this:

function first(callback){
    console.log("First");
    callback();
}

function second(callback){
    console.log("Second");
    callback();
}

function third(callback){
    console.log("Third");
}

With your code, the callback never would get executed.

Upvotes: 2

Related Questions