Search code examples
javascriptnode.jsasync-awaites6-promise

NodeJS async/await order not working


I'm new with NodeJS and Promises, so I might not been understanding how it works.

I'm loading a configuration file in my app, with the peculiarity that if it doesn't exist, I create it with the info from a call to database.

function getConfig(clientId, app) {
  return new Promise(async (resolve, reject) => {
    await fs.access(config.files.url_networks_file, async function(err) {
      if (err) {
        try {
          await loadClientConfig(clientId);
        } catch (e) {
          reject(e);
        }
      }
    });

    fs.readFile(config.files.url_networks_file, 'utf8', function(err, data) { // Try to read network's configuration file
      if (err) { // If file doesn't exists
        reject(err);
      } else if (JSON.parse(data)[app]) { // In case app's config exists
        resolve(JSON.parse(data)[app]);
      } else { // In case app's config doesn't exists
        reject(new Error('There\'s no configuration for app: ' + app));
      }
    });
  });
}

My problem is that fs.readFile() doesn't waits until loadClientConfig() finish, so it always return "file not found". If the config file already exists, it works perfectly.

I've tried putting fs.readFile() inside the fs.access() callback, still not getting anything (even if the file exists).

UPDATE

Still not working with the two solutions I received. I'm posting the code I made for each one to check if I lost something in the coding:

@Quentin

async function loadClientConfig(clientId) {
    return new Promise((resolve, reject) => {
        fs.access(config.files.url_networks_file, function (err) {
            if (err) {
                try {
                    sql.close();
                    sql.connect(config.database.credentials, function (err) {
                        if (err) {
                            reject(err);
                        } else {
                            var request = new sql.Request();
                            request.input('clientId', clientId);
                            query = config.database.queries.all;

                            request.query(query, function (e, data) {
                                if (e) {
                                    reject(e);
                                } else {
                                    try {
                                        resolve(writeConfigFile(data.recordset));
                                    } catch (err) {
                                        reject(err);
                                    }
                                }
                            });
                        }
                    });
                } catch (e) {
                    reject(e);
                }
            }
        });
    });
};

async function getConfig(clientId, app) {
  return new Promise(async (resolve, reject) => {
    try {
      await loadClientConfig(clientId);
    } catch (e) {
      reject(e);
    }

    fs.readFile(config.files.url_networks_file, 'utf8', function(err, data) { // Try to read network's configuration file
      if (err) { // If file doesn't exists
        reject(err);
      } else if (JSON.parse(data)[app]) { // In case app's config exists
        resolve(JSON.parse(data)[app]);
      } else { // In case app's config doesn't exists
        reject(new Error('There\'s no configuration for app: ' + app));
      }
    });
  });
}

@dasfdsa

async function loadClientConfig(clientId) {
  return new Promise((resolve, reject) => {
    sql.close();
    sql.connect(config.database.credentials, function(err) {
      if (err) {
        reject(err);
      } else {
        var request = new sql.Request();
        request.input('clientId', clientId);
        query = config.database.queries.all;

        request.query(query, async function(e, data) {
          if (e) {
            reject(e);
          } else {              
            try {
              resolve(writeConfigFile(data.recordset));
            } catch (err) {
              reject(err);
            }
          }
        });
      }
    });
  });
};

async function getConfig(clientId, app) {
  await new Promise((resolve, reject) => {
    fs.access(config.files.url_networks_file, async function (err) {
      if (err) {
        try {
          let temp = await loadClientConfig(clientId); /*Now that you told me its async, we will await it as well*/
          resolve(temp);
        } catch (e) {
          reject(e);
        }
      } else {
        resolve();
      }
    });
  });
  let configuration = await new Promise((resolve, reject) => {
    fs.readFile(config.files.url_networks_file, 'utf8', function (err, data) { // Try to read network's configuration file
      if (err) { // If file doesn't exists
        reject(err);
      } else if (JSON.parse(data)[app]) { // In case app's config exists
        resolve(JSON.parse(data)[app]);
      } else { // In case app's config doesn't exists
        reject(new Error('There\'s no configuration for app: ' + app));
      }
    });
  });

  return configuration;
}

UPDATE 2

It seems that works when debugging, I'm using VSCode. I think it may be a timeout issue or something similar.


Solution

  • Code: Two separate awaited promise for each callback. getConfig returns a promise which will resolve to config.

    async function getConfig(clientId, app) {
        await new Promise((resolve, reject) => {
            fs.access(config.files.url_networks_file, async function (err) {
                if (err) {
                    try {
                        let temp = await loadClientConfig(clientId);/*Now that you told me its async, we will await it as well*/
                        resolve(temp);
                    } catch (e) {
                        reject(e);
                    }
                }
            });
        });
        let config = await new Promise((resolve, reject) => {
            fs.readFile(config.files.url_networks_file, 'utf8', function (err, data) { // Try to read network's configuration file
                if (err) { // If file doesn't exists
                    reject(err);
                } else if (JSON.parse(data)[app]) { // In case app's config exists
                    resolve(JSON.parse(data)[app]);
                } else { // In case app's config doesn't exists
                    reject(new Error('There\'s no configuration for app: ' + app));
                }
            });
        });
    
        return config;
    
    }
    

    Edit: I have edited to await loadClientConfig(), above code should work fine if loadClientConfig returns a promise.