Anderson Green
Anderson Green

Reputation: 31840

How can I specify the order in which node.js functions are evaluated?

Below, I tried to evaluate the im.identify before console.log(toObtain), but it appears that console.log(toObtain) was called after im.identify. How can I make sure that the functions are called in exactly the order that I want them to be called?

var toObtain; //I'm trying to set the value of this variable to features (inside the callback).

var im = require('imagemagick');
im.identify('kittens.png', function(err, features){
  if (err) throw err
  //console.log(features);
  toObtain = features;
  console.log(toObtain); //this prints { format: 'PNG', width: 400, height: 300, depth: 8 }
})

console.log(toObtain); //This function call is evaluated BEFORE im.identify, which is exactly the opposite of what I wanted to do.

Upvotes: 1

Views: 2487

Answers (3)

saeed
saeed

Reputation: 3923

This is how node works. This is normal async behaviour.

To save yourself from going nuts when working with node its important to break things up to functions that each have specific purpose. Each function will call the next passing parameters as needed.

var im = require('imagemagick');

var identify = function () {

      im.identify('kittens.png', function(err, features){

         doSomething(features) // call doSomething function passing features a parameter.

      })

}(); // this is the first function so it should self-execute.

var doSomething = function (features) {

       var toObtain = features;

       console.log(toObtain) //or whatever you want to do with toObtain variable
};

Upvotes: 2

Rob Raisch
Rob Raisch

Reputation: 17367

Asynchronous means that things occur when they are ready (without any synchronous relationship to each other.)

This implies that if you wish to print or otherwise operate on a value created within an asynchronous function, you MUST do so in its callback since that is the only place that the value is guaranteed to be available.

If you wish to order multiple activities so they occur one after another, you'll need to apply one of the various techniques which "chain" asynchronous functions in a synchronous way (one after another) such as the async javascript library written by caolan.

Using async in your example, you would:

var async=require('async');

var toObtain;

async.series([

  function(next){ // step one - call the function that sets toObtain

    im.identify('kittens.png', function(err, features){
      if (err) throw err;
      toObtain = features;
      next(); // invoke the callback provided by async
    });

  },

  function(next){ // step two - display it
    console.log('the value of toObtain is: %s',toObtain.toString());
  }
]);

The reason this works is because the async library provides a special callback that is used to move to the next function in the series which must be called when the current action has completed.

See the async documentation for further info, including how to pass values through the next() callback to the next function in the series and as the result of the async.series() function.

async can be installed to your application using:

npm install async

or globally, so it is available to all your nodejs applications, using:

npm install -g async

Upvotes: 2

billy
billy

Reputation: 1160

This is normal, since im.identify seams to be async (it requires a callback). Therefore, the callback can get executed after the next line.

EDIT : You therefore have to put any code that users toObtain IN your callback, after toObtain = features;

Upvotes: 0

Related Questions