Last interview question

This is the last question on a written JS assessment I have in front of me:

// Don't edit this
// assert is a validation function.
function assert(one, two) {
  if (one !== two) {
    throw new Error(`${one} is not equal to ${two}`);
  }
}
// End Don't edit this

// Don't edit this – Do read through; it is necessary for the next question.
/**
 * getResults takes a callback function that takes an array
 *
 * @param {function(number[])} cb
 * @returns {undefined}
 */
const getResults = (function () {
  let callNum = 0;
  let num = 0;
  let callResults = 10;
  let callTimes = 20;
​
  return function (cb) {
    if (callNum++ >= callTimes) {
      return setTimeout(cb, 0, []);
    }
​
    const res = [];
    for (let i = 0; i < callResults; i++) {
      res.push(num++);
    }
​
    return setTimeout(cb, 0, res);
  };
})();
// End Don't edit this
​
// QUESTION 9
// Change this implementation of `processResults` to keep calling getResults
// until you get no more results.  Then, call `cb` with an array of everything
// generated by `getResults`
function processResults(cb = (arr) => console.log(arr)) {
  getResults(cb);
}
​
// Don't edit this
processResults(arr => {
  assert(arr.length, (10 * 20));
  assert(arr[10], 10);
  assert(arr[90], 90);
});
// End Don't edit this

I created a fiddle to try and understand the flow of execution here, but no matter what I change in the processResults function, nothing seems to actually change when I run the code. What am I missing here?

You should be working this out on your own. That is the point of the assessment.

Not exactly the most helpful response, but here’s what I’ve done so far:

  • I set the code up in a fiddle and executed it
  • I put console log statements all over the place to try and better understand what’s happening (even in the parts I’m not supposed to edit). but since I’m missing something about how this works, it didn’t help.
  • I tried Googling for more information on callbacks, but again without knowing specifically what I’m searching for, I wasn’t able to find anything to help me.
  • So, the only other thing I could think of was to try and find some more information from this forum, which has proven useful in the past.

I’m not asking for the exact solution, but I am trying to get a better explanation than the flat file I had to start with, and I was hoping to ask some more questions to try and understand what’s going on here. If that’s not something you want to help with, then just stay out of it. But posting a response that boils down to “go away” or “don’t ask for help” is counter-productive, especially when the opening instructions explicitly say “Feel free to use any available resources”. This is an available resource, and I’m trying to use it.

I spent some more time fiddling around with this question, and it led to some more questions that I am unable to answer.

  • I tried to execute the line getResults(cb) a second and third time in the processResults function definition (the only part of the code that I’m technically allowed to edit), and I put a console log statement after the line res.push(num++) to show the contents of the res array. After the first call to getResults, res has the numbers from 0-9 like I would expect. However, each time I call getResults(cb) after that, the contents of the res array get wiped out (right above the start of the for loop that fills the array). How am I supposed to accumulate a bigger array if the results are wiped every time this function gets called?
  • I then tried to output the results of the getResults function call with console.log("RESULTS:",getResults(cb)), and to my surprise the return value was an integer “3”. I have no idea what that means or where it comes from. I tried it a second and third time and got integers “4” and “5”, respectively. Where does that come from?

I’m now more lost than ever. What the heck is going on here?

I hope I’m not being too cryptic or vague, but you should refresh your knowledge on closures. The function they’ve provided you makes use of a closure in order to maintain state. It’s definitely a concept you should understand if you plan to work with javascript frequently.

Just executing the code you/the test provided - with zero changes - will console.log the array values you’re getting back, which should give you a clear idea of what data you need to operate on.

EDIT: I said ‘without changes’, but a processResults() call with no parameters is required to produce the console output I refer to.

Hopefully that helps a little.

The function you’re asked not to edit returns the id of the setTimeout. If you look up the documentation on setTimeout, you’ll see that this id can be used to clear a timeout. It doesn’t appear relevant to the problem you’ve presented, but you should read up on it when time permits.

I can understand your frustration at RandellDawson’s response, but please appreciate that it’s a perilous balance between being helpful and simply doing someone’s work/test/assessment for them. It’s rarely clear cut to me how to deliver a useful response without crossing that line.

Welp, it’s been over a week of looking at this. I’ve researched closures and found this example: https://www.w3schools.com/js/js_function_closures.asp, and while it helps to make sense of the self-invoking call at the end of the getResults definition, it still doesn’t help solve the actual problem. I understand that closures are there to help gain access to variables within a function outside of said function, but I don’t understand how I’m supposed to make an array that’s greater than 10 numbers when that array resets itself every time the getResults function is executed. Can someone at least give me a hint, or point me in the right direction, or something?

So you do not want to reset the array to an empty array if the array already has elements? If so, then how do you check if an array has any elements? Or better yet, why do you need to reset the array anyway?

The first “assert” test that I need to pass implies that the array needs to grow to a size of 200 numbers, but the code that is labeled “do not change” in the instructions is resetting the res array back to an empty one, so I don’t know how to accumulate anything beyond ten numbers. I can even get it to increment which ten numbers every time I call the callback, but that’s still not good enough.

@tlannoye11
Place the original code you were given in a browser console or other JS execution environment. Add these calls

processResults();
processResults();
processResults();

And observe the output that is logged. (runnable pastebin example)
image
Without making any changes to the code provided in the question, processResults is calling the getResults function and passing it a callback. That callback is defined as

cb = (arr) => console.log(arr)

As the console output above demonstrates, it is clearly receiving a 10 element array of numbers with each call. Each of those arrays contains sequential integers.

Your first job amounts to creating a callback that saves and/or combines those individual return arrays instead of just logging them to the console. Focusing on the line that clears res is not helping - forget about it, and focus on the callback function you need to provide, the data it is receiving (a 10 element array of numbers with each call), and what you need to do with it (combine and save).

Here’s another pastebin example with a callback that logs the array and it’s length. Once you’ve got that idea going, you can decide how to save the result where you need it, and you can use the native Array functions to combine multiple arrays into your final result.

Other ideas that might help:

  • Each getResults call produces one (new) array of set length. You need a result longer than each individual, so use an appropriate looping structure to make multiple calls.
  • Callbacks are generally not synchronous. You will likely need to use one of the language features designed to work with asynchronous structure. I promise it will help.