How to handle modules in an asynchronous app in node.js

for (var i = 0; i < users.length; i++) {
  if (users[i].access_token !== undefined) {
    var syncer = require('dropsite_server/dbox_sync');
    var client = dboxApp.client(users[i].access_token);
    var websites_to_sync = [];
    syncer.doSync(client, users[i].website, users[i].access_token.uid);
  }
}

In syner.doSync I have some asynchronous function calls. And yes for performance reasons I want to keep them asynchronous. The issue is, that the syncer object is just a reference, so while doSync is working, the for-loop continues to run, which then changes the variables.

Right now the surrounding for loop has only two elements, result is, only the last element gets processed, but not only once, but actually twice.

The solution would be to make syncer a proper object, but somehow I fail. To get a better understanding of what the code in syncer looks like, here the beginning:

/**
* This here is the sync module. User needs to provide. All this module does,
* is sync from a users dropbox to a local path
*/
var dbox = require("dbox");
var fs = require("fs");
var async = require("async");

var allow_downloads = true;
var allow_local_deletes = true;

var client = null;
var saved_sync_data = null;
var sync_data_path = global.config.sync_data_file;
var uid = null;
var remote_sync_dirs = null;

//var sync_data_file = ".dropbox_sync_data";

var errors = [];

var queue = async.queue(doTask, 1);

exports.doSync = function (clientIn, website_domain, _uid) {
    client = clientIn;
    uid = _uid; 
    sync_data_path = sync_data_path + "_" + uid;
    remote_sync_dirs = website_domain;
    async.series(
      [
        readSyncDataFile,
        startSync
      ]);
}
/**
 * Start the Sync
 * @param  dbox client This is a dbox client
*/

function startSync() {
  console.log("get remote delta for website: " + remote_sync_dirs)
  getRemoteDelta();
}

var declarations are not scoped to loops, and should be made at the top of file/function

var syncer = require('dropsite_server/dbox_sync')
  , client
  , websites_to_sync = [] //what is this used for?

for (var i = 0; i < users.length; ++i) {
  if (users[i].access_token !== undefined) {
    client = dboxApp.client(users[i].access_token)
    syncer.doSync(client, users[i].website, users[i].access_token.uid);
  }
}

The reason the last item gets processed twice is that the doSync function sets module level variables that get overwritten each time you call it.

The way to fix this is to pass the variables to the function instead

exports.doSync = function (client, website_domain, uid) {
  sync_data_path = sync_data_path + "_" + uid
  remote_sync_dirs = website_domain

  async.series([
      readSyncDataFile.bind(null, client, website_domain, uid) 
    , startSync.bind(null, client, website_domain, uid) 
  ])
}

function startSync(client, website_domain, uid) {
  ...
}
function readSyncDataFile(client, website_domain, uid) {
  ...
}