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;
}
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.
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;
}
});
}