Home > Software design >  setTimeout and scope in javascript
setTimeout and scope in javascript

Time:12-12

I'm playing around with setTimeout, and I'm not getting the results I'd expect. I have an array by the name of cars, and I have a function called fetchCars which simply calls setTimeout and returns the cars after 1000 ms. As far as I know the setTimeout should have access to the cars array because of closures, but for some reason when I an await an invocation of fetchCars I don't get any results.

Here is a sandbox Here is my code:

const cars = [
  { brand: "Toyota", model: "Camry", year: "2014" },
  { brand: "BMW", year: "2016", model: "M3" },
  { brand: "Porche", model: "911", year: "2018" }
];
export const fetchCars = async () => {
  setTimeout(() => {
    return cars;
  }, 1000);
};

const recieveCars = async () => {
  const cars = await fetchCars();
  console.log(cars);
};
recieveCars();


///Console Output:  undefined

CodePudding user response:

The reason you're seeing undefined in your console is that fetchCars returns a Promise (only by virtue that you have tagged it with async) that resolves to undefined - in other words, it doesn't really return anything!

export const fetchCars = async () => {
  setTimeout(() => {
    // the callback you have passed to setTimeout will return cars, not the fetchCars function
    return cars;
  }, 1000);
};

If you want fetchCars to return a value, it needs to return a Promise that will resolve to the value you want to return.

// no need for async here, because we're going to be returning a Promise explicilty
export const fetchCars = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(cars);
    }, 1000);
  });
};

CodePudding user response:

setTimeout uses a callback and has no native Promise version. While Brendan's answer is correct and perfectly functional, another option that is more consistent with async/await style is to await the timeout promise in the async function, then return the value.

export const fetchCars = async () => {
  await new Promise((r) => setTimeout(r, 1000);

  return cars;
};

If you're doing this a lot, a convenience function like this:

const delay = (delayTime) => new Promise((r) => setTimeout(r, delayTime));

Will then let you write your function like:

export const fetchCars = async () => {
  await delay(1000);

  return cars;
};
  • Related