Marius
Marius

Reputation: 13

add a delay in a double loop

In this code (source: eloquent javascript) i want to add a delay of 1 second for any of these 2 loops but i do not manage in any way. I would like to see how that can be solved with setTimeout for each of loops and for both (each iteration to be executed 1 second one after the other, thank you. I failed to get this working from similar questions/answers.

let board = "";

for (let y = 0; y < 8; y++) {
  for (let x = 0; x < 8; x++) {
    if ((x + y) % 2 == 0) 
         {board += " ";}
    else {board += "#";}
  }
  board += "\n";
}

console.log(board);

Upvotes: 1

Views: 150

Answers (3)

Saptarsi
Saptarsi

Reputation: 888

var count = 0;
/*
Parameters:
    array: []
    fnc: function (the business logic in form of function-,what you want to execute)
    delay: milisecond    
*/
function delayLoop(array,fnc,delay){
    if(!array || array.legth == 0)return false;
    setTimeout(function(data){ 
        var data = array[count++];
        fnc && fnc(data);
        //recursion...
        if(count < array.length)
            delayLoop(array,fnc,delay);
        else count = 0;     
    },delay);
}

Upvotes: 0

VLAZ
VLAZ

Reputation: 29022

We can split up your display and processing logic via a very simple implementation of the publish-subscribe pattern. We need basically threse things

  • A message queue or message channel. In this case we could use an array - no reason not to, as it's the simplest to implement it.
  • A publisher will add messages to the queue. In this case, the algorithm you do would be adding board every time.
  • A subscriber that will do something with each entry in the array. In this case, simply print it to the console.
  • A message broker - this is typically the part that sends the messages to subscribers. Here, we can use a simple setInterval that would do periodic polling of the message queue and if there are messages, would forward them.

A commercial publish-subscribe system is likely to have a lot of bells and whistles - multiple queues/channels, message filtering, topics, storage of consumed events, etc. We don't really need all of that for this case but it's useful to mention that the following is an example of how pub-sub systems work, rather than a full implementation. Still, we don't necessarily need all of that for this problem. Here is a rudimentary implementation:

//the message queue
let queue = [];

//our message broker
setInterval(
  () => {
    if (queue.length !== 0) {
      const frame = queue.shift();
      //our subscriber
      print(frame);
    }
  },
  1000
);

//our publisher
function calculate() {
  let board = "";

  for (let y = 0; y < 8; y++) {
    for (let x = 0; x < 8; x++) {
      if ((x + y) % 2 == 0) 
           {board += " ";}
      else {board += "#";}
    }
    board += "\n";

    queue.push(board); //the publish action
  }
}

calculate();


//just print to the console
function print(frame) {
  console.log(frame)
}

As mentioned, this is an overview of how this can work. Note that the implementation is closer to observer but doesn't act at the same moment as the change. At times design patterns may blur the lines between each other, especially depending on how they are used.

At any rate, the advantage of this pattern is that you can decouple your display (data consumption) logic to the calculations (data production). Your algorithm doesn't need to change if you want to add different consumers for the data it produces.

We can expand this to include multiple subscribers easily:

let queue = [];
let subscribers = [];

//add to a pool of subscribers that will all run on the same schedule and consume messages
function subscribe(callback) {
  subscribers.push(callback);
}

setInterval(
  () => {
    if (queue.length !== 0) {
      const frame = queue.shift();
      subscribers.forEach(sub => sub(frame));
    }
  },
  1000
);

function calculate() {
  let board = "";

  for (let y = 0; y < 8; y++) {
    for (let x = 0; x < 8; x++) {
      if ((x + y) % 2 == 0) 
           {board += " ";}
      else {board += "#";}
    }
    board += "\n";

    queue.push(board);
  }
}

subscribe(print);
subscribe(displayHTML);

calculate();


//just print to the console
function print(frame) {
  console.log(frame);
}

//show as HTML on the page
function displayHTML(frame) {
  const displayElement = document.getElementById("display_area");
    //convert newlines for HTML display
    const displayFrame = frame
      .replace(/\n/g, '<br/>') //new lines to <br/> tags
      .replace(/ /g, '&nbsp'); //spaces to non-breakable spaces
    displayElement.innerHTML = displayFrame;
}
.as-console-wrapper {
  /* resize the console otherwise it covers up the HTML display */
  left: 300px !important;
}
<div id="display_area"></div>

Or here is a minor variation where you can add subscribers that work at different schedules:

let queue = [];

//add different subscribers that might work at different times through the messages
function subscribe(subscriberCallback, pollTimeMs) {
  let lastFrameIndex = 0;
  setInterval(
    () => {
      if (queue.length !== lastFrameIndex) {
        //next message in the queue for this subscriber
        const frame = queue[lastFrameIndex++];
        subscriberCallback(frame);
      }
    },
    pollTimeMs
  );
}

function calculate() {
  let board = "";

  for (let y = 0; y < 8; y++) {
    for (let x = 0; x < 8; x++) {
      if ((x + y) % 2 == 0) 
           {board += " ";}
      else {board += "#";}
    }
    board += "\n";

    queue.push(board);
  }
}

subscribe(print, 1000);
subscribe(displayHTML, 1500);

calculate();


//just print to the console
function print(frame) {
  console.log(frame);
}

//show as HTML on the page
function displayHTML(frame) {
  const displayElement = document.getElementById("display_area");
    //convert newlines for HTML display
    const displayFrame = frame
      .replace(/\n/g, '<br/>') //new lines to <br/> tags
      .replace(/ /g, '&nbsp'); //spaces to non-breakable spaces
    displayElement.innerHTML = displayFrame;
}
.as-console-wrapper {
  /* resize the console otherwise it covers up the HTML display */
  left: 300px !important;
}
<div id="display_area"></div>

Upvotes: 1

nick zoum
nick zoum

Reputation: 7285

You could use generators in combination with setinterval to call iterator#next every second. So in the following example, just do yield board whenever you want to wait 1 second.

function* looping() {
  let board = "";
  for (let y = 0; y < 8; y++) {
    for (let x = 0; x < 8; x++) {
      board += (x + y) % 2 ? "#" : " ";
      yield board;
    }
    board += "\n";
  }
  return board;
}

var iterator = looping();

(function iife() {
  setTimeout(function() {
    var result = iterator.next();
    document.querySelector("#result").textContent = result.value;
    if (!result.done) iife();
    else console.log("Done");
  }, 1000);
})();
#result {
  white-space: pre;
}

#result::before,
#result::after {
  content: '"';
}
<div id="result"></div>

Upvotes: 2

Related Questions