skip to Main Content

I’m new to node js.
Logically, await should wait for the function to complete and then next line of code should run, but in my function, it doesn’t wait for process (2) to finish even after using await. What am I missing?

const getDefaultTemplates = async (token) => {
  const emailertoken = process.env.EMAILER_AUTH_TOKEN;
  const key = 'defaultTemplates';
  // This should run first
  console.log('hi');
  let defaultTemplatesVar = '';
  let fromCache = 0;

  // This should run second. Need response from redisClient to return parent function
  const defaultTemplates = await redisClient.get(key, (err, data) => {
    if (err) {
      console.log(err);
    }
    // If data is found in cache
    if (data != null) {
      console.log('from cache');
      defaultTemplatesVar = JSON.parse(data);
      fromCache = 1;
      console.log('defaultTemplatesVar1 = ', defaultTemplatesVar);
    }
    return defaultTemplatesVar;
  });

  console.log('defaultTemplatesVar2 = ', defaultTemplatesVar);
  console.log('fromCache = ', fromCache);
  if (fromCache === 0) {
    // If data is not found in cache, call api
    // console.log('from api');
    try {
      const response = await axios.get(`${process.env.EMAILER_API_URL}/get-system-templates`, {
        headers: {
          Authorization: `bearer ${emailertoken}`,
        },
      });
      console.log('from data');
      redisClient.setex(key, 3600, JSON.stringify(response.data._embedded.get_system_templates));
      defaultTemplatesVar = response.data._embedded.get_system_templates;
      console.log('defaultTemplatesVar3 = ', defaultTemplatesVar);
    } catch (error) {
      console.error(error);
    }
  }

  // This should run at last, to return value to parent function getDefaultTemplates()
  console.log('bye');
  console.log('defaultTemplatesVar4 = ', defaultTemplatesVar);
  return defaultTemplates;
};


OUTPUT ->

hi
defaultTemplatesVar2 =  
fromCache =  0
from cache
defaultTemplatesVar1 =  [ { name: 'versafix-1', description: 'The versatile template' },
  { name: 'givecentral', description: 'The Givecentral Template' } ]
from data
defaultTemplatesVar3 =  [ { name: 'versafix-1', description: 'The versatile template' },
  { name: 'givecentral', description: 'The Givecentral Template' } ]
bye
defaultTemplatesVar4 =  [ { name: 'versafix-1', description: 'The versatile template' },
  { name: 'givecentral', description: 'The Givecentral Template' } ]

Output should be in series of 1,2,3,4.

2

Answers


  1. Chosen as BEST ANSWER

    My issue was solved from Allen's Answer.

    Only thing I changed in Allen's suggestion was

    const data = await redisGet(key);

    Instead of

    const data = await redisClient.get(key);

    because the later one returned 'true' instead of actual values.

    const redisGet = (key) => new Promise((resolve, reject) => {
      redisClient.get(key, (err, data) => {
        if (err) return reject(err);
        return resolve(data);
      });
    });
    
    // Api,Auth Done
    const getDefaultTemplates = async (token) => {
      const emailertoken = process.env.EMAILER_AUTH_TOKEN;
      const key = 'defaultTemplates';
      // This should run first
      console.log('hi');
      let defaultTemplatesVar = '';
      let fromCache = 0;
    
      // This should run second. Need response from redisClient to return parent function
      try {
        const data = await redisGet(key);
    
        if (data != null) {
          console.log('from cache');
          defaultTemplatesVar = JSON.parse(data);
          fromCache = 1;
          console.log('defaultTemplatesVar1 = ', defaultTemplatesVar);
        }
        const defaultTemplates = defaultTemplatesVar;
      } catch (err) {
        console.error(err);
      }
    
      console.log('defaultTemplatesVar2 = ', defaultTemplatesVar);
      console.log('fromCache = ', fromCache);
      if (fromCache === 0) {
        // If data is not found in cache, call api
        // console.log('from api');
        try {
          const response = await axios.get(`${process.env.EMAILER_API_URL}/get-system-templates`, {
            headers: {
              Authorization: `bearer ${emailertoken}`,
            },
          });
          console.log('from data');
          redisClient.setex(key, 3600, JSON.stringify(response.data._embedded.get_system_templates));
          defaultTemplatesVar = response.data._embedded.get_system_templates;
          console.log('defaultTemplatesVar3 = ', defaultTemplatesVar);
        } catch (error) {
          console.error(error);
        }
      }
    
      // This should run at last, to return value to parent function getDefaultTemplates()
      console.log('bye');
      console.log('defaultTemplatesVar4 = ', defaultTemplatesVar);
      return defaultTemplatesVar;
    };
    

    OUTPUT 1 (When data comes from the API)

    hi
    defaultTemplatesVar2 = 
    fromCache =  0
    from data
    defaultTemplatesVar3 =  [ { name: 'versafix-1', description: 'The versatile template' },
      { name: 'givecentral', description: 'The Givecentral Template' } ]
    bye
    defaultTemplatesVar4 =  [ { name: 'versafix-1', description: 'The versatile template' },
      { name: 'givecentral', description: 'The Givecentral Template' } ]
    
    

    OUTPUT 2 (When Data comes from Cache)

    hi
    from cache
    defaultTemplatesVar1 =  [ { name: 'versafix-1', description: 'The versatile template' },
      { name: 'givecentral', description: 'The Givecentral Template' } ]
    defaultTemplatesVar2 =  [ { name: 'versafix-1', description: 'The versatile template' },
      { name: 'givecentral', description: 'The Givecentral Template' } ]
    fromCache =  1
    bye
    defaultTemplatesVar4 =  [ { name: 'versafix-1', description: 'The versatile template' },
      { name: 'givecentral', description: 'The Givecentral Template' } ]
    

  2. Callback function can not be await,
    To turn callback fn to Promise fn, check out https://www.npmjs.com/package/redis#promises .

    If you are using other packages, you actually can turn callback to promise by

    const redisGet = (key) => new Promise((resolve, reject) => {
      redisClient.get(key, (err, data) => {
        if (err) return reject(err);
        return resolve(data);
      });
    });
    
    // So you can do
    const data = await redisGet(key);
    // or
    redisGet(key).then((data) => { ... }).catch((err) => { ... });
    

    so what you should do

    try {
      ...
    
      const data = await redisClient.get(key);
    
      if (data != null) {
        console.log('from cache');
        defaultTemplatesVar = JSON.parse(data);
        fromCache = 1;
        console.log('defaultTemplatesVar1 = ', defaultTemplatesVar);
      }
      const defaultTemplates = defaultTemplatesVar;
      ...
    } catch (err) {
      console.error(err);
    }
    

    Simple tutorial about Callback vs Promise

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search