Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

execute promises recursively nodejs

the following function creates new folder on my server via xmlrpc

var createFolder = function(folder_name) {
  var defer = Q.defer();
  client.methodCall('create_folder', [sessionID, folder_name], function(err, resp) {
    if (err) {
      if (err.responseString && err.responseString.match('already exist')) {
        //call the same function recursively with folder_name+Math.round(Math.random()*100)
      } else {
        defer.reject(err);
      }
    } else {
      defer.resolve(folder_name);
    }
  });
  return defer.promise;
}

The functions creates a new folder successfully However, if folder already exists i want to fire this function again recursively with new folder name and then return it in promise so that whenever this function is called it'll return the folder name doesn't matter how many times it was executed

something like

createFolder('directory').then(function(resp){
 console.log(resp);// may return directory || directory1 .... etc
});

**EDIT ** so i manged to achieve this by passing the defer object let me know if there are more elegant ways of achieving this

var createFolder = function(folder_name,defer) {
  defer =defer ||  Q.defer();
  client.methodCall('create_folder', [sessionID, folder_name], function(err, resp) {
    if (err) {
      if (err.responseString && err.responseString.match('already exist')) {
        return createFolder(folder_name+Math.round(Math.random()*100,defer)
      } else {
        defer.reject(err);
      }
    } else {
      defer.resolve(folder_name);
    }
  });
  return defer.promise;
}
like image 255
ahhmarr Avatar asked Dec 31 '25 23:12

ahhmarr


2 Answers

Never do any logic in plain (non-promise) callbacks. Promisify at the lowest level:

var defer = Q.defer();
client.methodCall('create_folder', [sessionID, folder_name], function(err, resp) {
  if (err) defer.reject(err);
  else defer.resolve(folder_name);
});
return defer.promise;

Or much simpler with Q.ninvoke:

return Q.ninvoke(client, 'methodCall', 'create_folder', [sessionID, folder_name]);

Now we can start implementing our recursion. It's quite simple with a then callback, from which you can return another promise. In your case:

function createFolder(folder_name) {
  return Q.ninvoke(client, 'methodCall', 'create_folder', [sessionID, folder_name])
    .catch(function(err) {
      if (err.responseString && err.responseString.match('already exist')) {
        return createFolder(folder_name+Math.floor(Math.random()*100));
      } else {
        throw err;
      }
    });
}
like image 148
Bergi Avatar answered Jan 02 '26 13:01

Bergi


Here is a bad simple way of solving your problem:

var createFolder = function(folder_name) {
  var defer = Q.defer();
  client.methodCall('create_folder', [sessionID, folder_name], function(err, resp) {
    if (err) {
      if (err.responseString && err.responseString.match('already exist')) {
        //call the same function recursively with folder_name+Math.round(Math.random()*100)
        defer.resolve(createFolder(folder_name+Math.round(Math.random()*100)));
      } else {
        defer.reject(err);
      }
    } else {
      defer.resolve(folder_name);
    }
  });
  return defer.promise;
}

However, defer is considered bad practice. Here is a very nice article about promises.

You should favor something like:

var createFolder = function(folder_name) {
  return Q.Promise(function(resolve, reject){
     client.methodCall('create_folder', [sessionID, folder_name], function(err, resp) {
        if (err) {
          if (err.responseString && err.responseString.match('already exist')) {
            //call the same function recursively with folder_name+Math.round(Math.random()*100)
            resolve(createFolder(folder_name+Math.round(Math.random()*100)));
          } else {
            reject(err);
          }
        } else {
          resolve(folder_name);
        }
      });
  });
}

EDIT: as noted by @Bergi, this is still not right and hard to debug. Any potential errors thrown from the callback of methodCall won't actually reject the promise and will most likely be swallowed (even though this callback seems very little error-prone, it might evolve). Please refer to his answer for a better way of doing this.

Also, see the official Q doc here.

like image 20
Quentin Roy Avatar answered Jan 02 '26 13:01

Quentin Roy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!