javascript exercise of sequential callback

Viewed 140

I'm studying javascript and I rewrote this code from a book:

var controller = {};
controller.queue=[];
controller.add = function (func) {
                  controller.queue.push(func);
                 };
controller.run = function () {
                  controller.queue.shift() (controller.run);
                  
                 }

function longRunA(callback){
  console.log("A");
  setTimeout(callback,2000);
}
function longRunB(callback){
  console.log("B");
  setTimeout(callback,1000);
}

controller.add(longRunA);
controller.add(longRunB);
controller.run();

The printout is correct, A following two seconds after B, this is what he had to do.

Some things are not clear to me.

  1. Why does he write controller.run in parentheses after calling controller.queue.shift ()? I don't understand if it is done to make the function recursive, and I don't understand the role of the round brackets surrounding controller.run. The console reports this problem: uncaught typeerror: controller.queue.shift (..) is not a function at controller.run
  2. controller.add is called with longRunA argument, but I don't understand why it is correct to call longRunA function without arguments. I would have removed the word callback in the function definition.
3 Answers

Functions in Javascript can be:

  • passed to other functions as arguments
  • returned from inside of another function
  • saved inside a data structure such as array
  • assigned to variables

For more details, see: MDN - First-Class Function


Coming to the different questions you have regarding the code in question.

why does he write controller.run in parentheses after calling controller.queue.shift ()

If the controller.queue.shift() returns a function, then you can invoke it by adding parenthesis after it and just like any other function, you can pass arguments to it. In this case, controller.run is passed as an argument to the function returned by controller.queue.shift()

Following code snippet shows an example:

function sayHi(name) {
  console.log("Hi " + name + "!");
}

const arr = [sayHi];

arr.shift()("John");

In the above code snippet, arr.shift() returns the sayHi function which we then invoke using the parenthesis () and pass "John" as an argument.

The console reports this problem: uncaught typeerror: controller.queue.shift (..) is not a function at controller.run

You get this error because inside longRunB function, you call the callback function, i.e. controller.run but when that function is called, it tries to get the first element of controller.queue array but at this point, it is empty.

One way to solve this issue is to make sure that controller.queue.shift() gives you a function before trying to invoke it.

controller.add is called with longRunA argument, but I don't understand why it is correct to call longRunA function without arguments

controller.add is a function to which longRunA is being passed as an argument. longRunA is not being called here.

ok, thanks to your answers I understand the mistake. The last call to the callback function has to be commented out, because there are no more functions:

function longRunB (callback) {
   console.log ("B");
   // setTimeout (callback, 1000);
} 

for prevent the error you can use a while loop.

var controller = {};
controller.queue=[];
controller.add = function (func) {
                  controller.queue.push(func);
                 };
controller.run = function () {
                  while ( controller.queue.length > 0) {
                         controller.queue.shift()(controller.run);
                      }
                  } 
                  

function longRunA(callback){
  console.log("A");
  setTimeout(callback,2000);
}
function longRunB(callback){
  console.log("B");
  setInterval(callback,1000);
}

controller.add(longRunA);
controller.add(longRunB);
controller.run();
Related