1

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.

3
  • Change this line to const defaultTemplates = await redisClient.get(key) Commented Jul 17, 2020 at 8:54
  • Can you please elaborate? if I remove (err,data) then how am I supposed to check if there's any data or error? @KunalMukherjee Commented Jul 17, 2020 at 9:04
  • 2
    You shouldn't mix callbacks with promise, if error comes while fetching the redis key, it should go to the catch block Commented Jul 17, 2020 at 9:21

2 Answers 2

1

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

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! This solved my problem and I got the desired result.
0

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' } ]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.