Phased execution recursive cycle in Node.js

I'm new to Node.js and asynchronous programming in general, and I have a problem. I need for continuous work server in a recursive loop, which steps would be implemented consistently, and each stage should consist of an asynchronous receive data over websotskets (this is already has understood), or go to next stage on the expiration of timer. I am aware that is it not a trivial task, but how to implement it, what libraries can help? I tried to understand the Step.js and Node.js events, this is what i need?

If I wrote all this in sync:

//CODE FOR STACKOVERFLOW
var previous_round = 'qwerty';// this is string, selected in previous cycle
var round_users = users;// 'users' is array of soceket.id all connected users and here a put them into new array 'round_users' with sockets for current cycle
io.sockets.emit('users_round', { number: round_users.length }); // send to users information about number of users in new round
for (var i = 0; i < round_users.length; i++) {
      io.sockets.socket(round_users[i]).emit('round', { text: previous_round });//for each socket in 'round_users' emit event to enter chat message
}                                                                               // and send selected in previous round message
var messages = []; // array of users messages
//now we must listen users events and start timer for next stage
  //listen users events
  for (var i = 0; i < round_users.length; i++) {
        io.sockets.socket(round_users[i]).on('message', function (data) {
          messages[messages.length] = data.text;//write text from users to array
          if (messages.length == round_users.length) { /* GO TO NEXT STAGE */ } // it's after previous operation in this function
        });
  } 
  //or set timeout
  setTimeout(/* GO TO NEXT STAGE */,15000);
for (var i = 0; i < round_users.length; i++) {
      io.sockets.socket(round_users[i]).emit('voting', { messages_array: messages });//for each socket in 'round_users' emit event to vote perfect chat message
}                                                                                    // and send messages, which they send to server
//i'm not quite sure about this decision of vote counting :-)
var votes = []; //array with users votes
for (var i = 0; i < messages.length; i++) {
      votes[i] = 0;
}   
//now we must listen users events and start timer
  //listen users events
  for (var i = 0; i < round_users.length; i++) {
        io.sockets.socket(round_users[i]).on('vote', function (data) {
          votes[data.number]++;//increment selected message
          if (votes.length == messages.length) { /* GO TO NEXT STAGE */ } // it's after previous operation in this function
        });
  } 
  //or set timeout
  setTimeout(/* GO TO NEXT STAGE */,10000);
var max_id = 0; //now select max number from 'votes' array
for (var i = 0; i < votes.length; i++) {
      if (votes[i]>votes[max_id]) {max_id = i;} //yet without the same values
}   
var previous_round = messages[max_id]; //set up string value of selected message
//restart cycle

this code on pastebin with syntax highlighting

Recursion in the most basic sense is just a function that calls itself over and again, but in this instance with node you may want to utilize process.nextTick() to allow other events to occur during this recursion.

Here is a simple example of one way you might be able to go about it:

function someFunction(args, callback) {
  // Check requirements
  if (typeof callback !== 'function') return console.log('Callback required');
  if (typeof args === 'undefined') return callback('Arguments required');

  // Set defaults
  var err = false;
  var result = false;

  // Do other stuff
  anotherFunctionWithAcallback(args, function(err, result) {
    if (err) return callback(err);
    // This way, the nextTick only occurs after processing completes
    return callback(err, result); 
  }
}

(function loop(stage) {
  // When the stage argument is not provided, default to stage 1
  stage = (typeof stage === 'undefined') ? 1 : stage;
  switch(stage) {
    case 1:
      /* stage 1 */
      someFunction(args, function(err, result){
        process.nextTick(loop(2));
      });
    break;
    case 2:
      /* stage 2 */
      someFunction(args, function(err, result){
        process.nextTick(loop(3));
      });
    break;
    case 3:
      /* stage 3 */
      someFunction(args, function(err, result){
        // No stage argument, restart at stage 1 by default
        process.nextTick(loop());
      });
    break;
  }
})(); // Execute this function immediately