0

I have been trying to get the result of this asynchronous function to no degree of success for the past few hours. I have checked the past similar questions and solutions but nothing has worked for this specific case.

This particular code below logs the value when I run console.log:

const okay = async () => {
  console.log(await getTimezoneLabel(timezone));
};

okay();

The code below logs Promise {pending} instead of a value to the console which is baffling

const okay = async () => {
  return await getTimezoneLabel(timezone);
};

let result = okay();

console.log(result);

Here is the getTimezoneLabel function itself:

async function getTimezoneLabel(timezone) {
  const timezoneObject = await convertTimezone('original', timezone);
  return timezoneObject[0].label;
}

Here is the convertTimezone function which the getTimezoneLabel function references:

import timezonesList from '../timezone-list';

async function convertTimezone(labelStyle, timezone) {
  const spacetime = (await import('spacetime')).default;
  const soft = (await import('timezone-soft')).default;

  const timezones = Object.fromEntries(Object.entries(timezonesList).filter(([key]) => key.includes(timezone)));

  return Object.entries(timezones)
    .reduce((selectOptions, zone) => {
      const now = spacetime.now(zone[0]);
      const tz = now.timezone();
      const tzStrings = soft(zone[0]);

      let label = '';
      let abbr = now.isDST()
        ? // @ts-expect-error
          tzStrings[0].daylight?.abbr
        : // @ts-expect-error
          tzStrings[0].standard?.abbr;
      let altName = now.isDST() ? tzStrings[0].daylight?.name : tzStrings[0].standard?.name;

      const min = tz.current.offset * 60;
      const hr = `${(min / 60) ^ 0}:` + (min % 60 === 0 ? '00' : Math.abs(min % 60));
      const prefix = `(GMT${hr.includes('-') ? hr : `+${hr}`}) ${zone[1]}`;

      switch (labelStyle) {
        case 'original':
          label = prefix;
          break;
        case 'altName':
          label = `${prefix} ${altName?.length ? `(${altName})` : ''}`;
          break;
        case 'abbrev':
          label = `${prefix} ${abbr?.length < 5 ? `(${abbr})` : ''}`;
          break;
        default:
          label = `${prefix}`;
      }

      selectOptions.push({
        value: tz.name,
        label: label,
        offset: tz.current.offset,
        abbrev: abbr,
        altName: altName,
      });

      return selectOptions;
    }, [])
    .sort((a, b) => a.offset - b.offset);
}

How can I get this to work?

Thank you so much in advance.

Idris
  • 558
  • 7
  • 29
  • `getTimezoneLabel()` is an `async` function and those always return a `Promise`. But why is the function marked as `async`? Why would `convertTimezone()` have to be asynchronous? Those `import`s don't have to be part of the function. – Andreas Aug 25 '22 at 11:11
  • @Andreas I am using Next JS dynamic imports. Where can I put the import if not inside the function – Idris Aug 25 '22 at 11:23

3 Answers3

3

I'm simplifying quite a lot here, but it helps to understand. When you declare a function as async, what it does is wrap the function in a Promise. So, for example, this function :

async function something(){ return "hello world" }

can be read like :

function something(){
  return new Promise((resolve, reject) => {
    resolve("hello world")
  })
}

In a nutshell, a Promise just schedules the execution of a function (in this case something) for later. So, we can only read the returned value later, when it's ready. When you call something(), it returns a Promise which is pending because it hasn't been executed yet (its execution is put on hold in a queue). You can learn more about how this works by reading about the event loop, the call stack and event queue.

To get the returned value of a Promise, we use a method called .then((value) => {}) which returns in the variable value the returned value of the function (in our case, value will contain "hello world"). So :

let r = something()
console.log(r) // Promise pending
r.then((value) => {
  console.log(value) // "hello world"
})

If you want to use the value, you are gonna have to either :

  • Put your code inside the .then() and continue there
  • Put your code inside an async function and use await in front of the call
async function run(){
  let value = await something()
  console.log(value) // "hello world"
  // do things with value
}

run()
joprocorp
  • 176
  • 10
  • Yes. Thank you very much for your explanation. I can console the value but how I return the value to a variable is the issue here. instead of console.log(value), passing ```val = value;``` doesn't do anything and the val variable still returns undefined – Idris Aug 25 '22 at 11:54
  • 1
    You are either going to have to put the rest of your logic inside the `.then()` or put your entire code inside an async function and put an await in front of the call : `let val = await something()`. This is one of the subtilities of asynchronous programming and javascript in general you're gonna have to deal with. – joprocorp Aug 25 '22 at 11:58
1

An async function return a promise. Try that:

const okay = async () => {
  return await getTimezoneLabel(timezone);
};

okay().then(result=>console.log(result));

or if you call okay() inside another async function you may use await syntax:

// should be inside async function
const result = await okay();
Andrey Smolko
  • 712
  • 3
  • 8
1

This is a similar question that is already answered with some good explanation

Well basically async function returns a promise. You can use use let somevariable = await okay() inside an async function OR You could do it like

okay().then((resp)=>{
   console.log(resp)
})