Repeating promises in Node.js through recursive execution

Here is a function that allows you to create a new folder on the server using 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 function successfully creates a new folder. However, if the folder already exists, the function will be called again recursively with a new folder name. The promise will always return the folder name, no matter how many times the function is executed.

For example:

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

**EDIT** I have managed 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;
}

Answer №1

Avoid performing any logic in regular callbacks, instead opt for promise-based functions 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;

Alternatively, simplify the process using Q.ninvoke:

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

Now we can move on to implementing our recursion. It becomes straightforward with a then callback where you can return another promise. In your scenario:

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

Answer №2

Let's explore a simplistic but not recommended method to address your issue:

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, it is worth noting that using defer is discouraged. Check out this informative article about promises.

It is advisable to opt for a structure like this:

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: @Bergi has pointed out that there are still issues with this approach and debugging may become challenging. Any possible errors generated from the callback of methodCall might not properly reject the promise. For an improved solution, refer to his response.

For more information, visit the official Q documentation here.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Unable to execute node file in Visual Studio Code's terminal

My attempt to run a file using the terminal in Visual Studio Code has hit a snag. Despite my best efforts, I keep encountering an error message that reads as follows: For example, when I type "node myfile.js" into the terminal, I get the following error: ...

Is there a way to efficiently line up and run several promises simultaneously while using just one callback function?

I am currently utilizing the http request library called got. This package makes handling asynchronous http connections fast and easy. However, I have encountered a challenge with got being a promisified package, which presents certain difficulties for me ...

Exploring the world of middleware in Express

I'm exploring the workings of middleware in Express. While I grasp the general idea of middleware, I find myself puzzled by the parameters involved. For instance, consider this snippet from the official middleware documentation: app.use('/user ...

Guide to efficiently executing multiple MySQL queries within a single request using Node.js, Express.js, MySQL2, and Promises

I am exploring the most efficient way to utilize AWAIT with MySQL2 in a Node.js/Express.js application when handling multiple queries within a single request. At the beginning of my application, I establish a Promise Pool from my Database configuration. ...

An error occurred with the instruction 'npm install *' due to its illegality

Attempting to install packages following this tutorial. However, the command npm install --save express body-parser connect-multiparty sqlite3 bluebird path umzug bcrypt is throwing an error: Illegal instruction] \ rollbackFailedOptional: verb npm-s ...

Issue: ENOENT - The specified file or directory, './views/s.ejs', does not exist in Node.js Express

Encountering an error when attempting to render a file from the 'views' directory in the 'routes'. The specific error message is as follows: Error: Valid Login { [Error: ENOENT: no such file or directory, open './views/s ...

Tips for inserting a JSON object into a MySQL database

Received a JSONObject from the client: { "registerationId": 57502, "firstName": "Taha", "lastName": "Kirmani", "dob": "10-08-1988", "cnic": 4210137718361, "gender": "Male" } Currently parsing it as shown below: app.post('/addUser', ...

On which server is Opa's backend platform hosted?

Curious about the backend platform Opa is utilizing to communicate with browsers. My hunch is leaning towards Node.js. ...

The error being caused by JavaScript's asynchronous property

Encountering a challenge while setting up the registration page for my application. The setup involves a react front end and a node/express back end. The tasks to be performed in react are: Initiate a backend call to node to validate user existence If use ...

The different versions of NPM utilized throughout the software development and production process

Based on my understanding, it is advisable to maintain the same version of Node.js consistently from development to production stages of an application. But what about NPM? It seems like NVM keeps specific versions of NPM along with corresponding Node.js ...

An issue arises with eslint-plugin-security when attempting to lint the Mongoose exec() method, resulting in a

Currently utilizing Nodejs, Eslint ^7, and Mongoose ^5. I have incorporated the recommended rules from eslint-plugin-security ^1 into my .eslintrc.js as outlined below: parserOptions: { ecmaVersion: 2021, }, env: { commonjs: true, es6: true, brows ...

Jhipster command was not found and is not recognized as an internal or external command, executable program, or batch file

I recently attempted to install JHipster by following the instructions provided at and using the JHipster Quick Start guide. However, when trying to run it on my Windows 10 system, I encountered an error stating "jhipster is not recognized as an internal ...

Rendering on the server using react-router v4 and express.js

I've been working on implementing server-side rendering with the latest version of react-router v.4. I found a tutorial that I followed at this link: . However, when I refresh the browser, I encounter the following error: Invariant Violation: React.C ...

What is the method for configuring express-basic-auth to display a popup for entering a username and password?

My node.js app used to function properly with basicAuth as a module of node. The following code would prompt for a password and username when accessing the app. // start the UI var app = express(); app.use(express.basicAuth('me', 'openforme ...

Mongoose - Utilizing several models with a single schema

Currently using mongoose v5.2.17 and curious if it's feasible to have multiple models mapping to a single schema. In this case, the existing model is shown below: const mongoose = require('mongoose'); const validator = require('validat ...

Troubleshooting in Visual Studio Code for Node.js is experiencing difficulty initiating

I encountered an issue while trying to run a simple node debugging session on visual studio code which resulted in the following error message: Program 'node.dll' failed to run: No application is associated with the specified file The Debug Co ...

The excessive use of Selenium Webdriver for loops results in multiple browser windows being opened simultaneously, without allowing sufficient time for the

Is there a way to modify this code so that it doesn't open 150 browsers to google.com simultaneously? How can I make the loop wait until one browser finishes before opening another instance of google? const { Builder, By, Key, until } = require(& ...

Guide to utilizing @types/node in a Node.js application

Currently, I am using VSCode on Ubuntu 16.04 for my project. The node project was set up with the following commands: npm init tsc --init Within this project, a new file named index.ts has been created. The intention is to utilize fs and readline to read ...

Searching for relevant information using the Sequelize framework that is based on the provided

I've set up a database table to store information about people and their relationships, allowing for self-association of parents, children, cousins, etc. const People = sequelize.define('People', { gender: Sequelize.STRING, name: Sequel ...

Can someone tell me where `npm link` is registering commands on Ubuntu?

Scenario Operating on a NodeJS oclif CLI known as "mydemo," I utilized the npm link command to globally register and execute its commands. However, upon executing npm unlink mydemo to remove the registration, typing in the program's name resulted in ...