Skip to content

Instantly share code, notes, and snippets.

@obber
Last active October 6, 2018 03:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save obber/7a436b4ceee26973d2de95aaa70a4346 to your computer and use it in GitHub Desktop.
Save obber/7a436b4ceee26973d2de95aaa70a4346 to your computer and use it in GitHub Desktop.

Asynchronous Javascript (with callbacks)

Say that we have a function, getRandomDog that runs a callback function asynchronously with a dog object as an argument:

const getRandomName = function() {
  const names = ['puppy', 'buddy', 'sam'];
  return names[Math.floor(Math.random() * names.length)];
};

const getRandomDog = function(callback) {
  setTimeout(function() {
    const dog = {
      name: getRandomName(),
    };
    callback(dog);
  }, Math.floor(Math.random() * 2000));
};

What does this log? Where is the error in thinking?

var dog = getDog();
console.log(dog);

How do we actually log the dog?

(Give it a try before reading on)

// answer:
getRandomDog(function(dog) {
  console.log(dog);
});

Which dog gets logged first? dog1, or dog2?

getRandomDog(function(dog1) {
  console.log(dog1);
});

getRandomDog(function(dog2) {
  console.log(dog2);
});

Answer: It's a trick question; We don't know which one gets logged first.

Write a function called getTwoDogs

getTwoDogs should use getRandomDog twice, and call the callback with an array of two dogs in it as an argument. (The order of the dogs in the array does not matter)

const getTwoDogs = function(callback) {
  //
  // your code here
  //
};

// example usage:
getTwoDogs(function(dogs) {
  console.log(dogs); // [{ name: 'puppy' }, { name: 'sam' }]
});

Very Wrong Solution:

const getTwoDogs = function(callback) {
  return [getRandomDog(), getRandomDog()];
};

Incorrect Solution:

const getTwoDogs = function(callback) {
  const dog1 = getRandomDog();
  const dog2 = getRandomDog();
  callback([dog1, dog2]);
};

Naive Solution:

// answer
const getTwoDogs = function(callback) {
  getRandomDog(function(dog1) {
    getRandomDog(function(dog2) {
      callback([dog1, dog2]);
    });
  });
};

Why is this naive? How could it be improved?

Efficient (but not clean) Solution:

// answer
const getTwoDogs = function(callback) {
  const dogs = [];
  getRandomDog(function(dog1) {
    dogs.push(dog1);
    if (dogs.length === 2) {
      callback(dogs);
    }
  });
  getRandomDog(function(dog2) {
    dogs.push(dog2);
    if (dogs.length === 2) {
      callback(dogs);
    }
  });
};

Optimal Solution:

// answer
const getTwoDogs = function(callback) {
  const dogs = [];
  const handleNewDog = function(dog) {
    dogs.push(dog);
    if (dogs.length === 2) {
      callback(dogs);
    }
  };
  getRandomDog(handleNewDog);
  getRandomDog(handleNewDog);
};

Bonus: Write a function called getNDogs

getNDogs takes 2 arguments:

  1. a number, n, that specifies how many dogs to get
  2. a callback function, which is called with an array of n dogs as its argument.
getNDogs = function(n, callback) {
  //
  // your code here
  //
};

Based on optimal solution from getTwoDogs:

// answer
getNDogs = function(n, callback) {
  const dogs = [];
  const handleNewDog = function(dog) {
    dogs.push(dog);
    if (dogs.length === n) {
      callback(dogs);
    }
  };
  for (let i = 0; i < n; i++) {
    getRandomDog(handleNewDog);
  }
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment