1

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);
Marius
  • 13
  • 6
  • 1
    Do you mean, each iteration to happen a second after the other? Or to entire `for` to start a second after? It's not very clear – Calvin Nunes Jan 21 '20 at 11:36
  • May be this can help you [Link](https://stackoverflow.com/a/3583740/11719787) – Sameer Jan 21 '20 at 11:37
  • Does this answer your question? [What is the JavaScript version of sleep()?](https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep) – Harun Yilmaz Jan 21 '20 at 11:37
  • i mean the program to not run instant as it is now and wait 1 second each time it increase it's x or y – Marius Jan 21 '20 at 11:37
  • So, each iteration of each `for` to happen 1 second after the other? If not this, please, [edit] the question to show with more clarity where you want to "delay" – Calvin Nunes Jan 21 '20 at 11:41
  • This looks like a rudimentary visualisation or game engine. Usually, with those you get the calculations done *first* and then the application shows what's happening in a way the user can follow. So, you can just run this loop to completion but add a delay to the *effects* that the loop would have. – VLAZ Jan 21 '20 at 11:44

3 Answers3

2

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>
nick zoum
  • 7,216
  • 7
  • 36
  • 80
  • 2
    The only thing I can say here: is `1E3` really worth shortening one symbol? I only noticed it because I wanted to change the animation speed and scanned the code for `1000` and couldn't see it. – VLAZ Jan 21 '20 at 11:53
  • @VLAZ Fair enough, changed it. – nick zoum Jan 21 '20 at 11:55
  • @VLAZ What do you mean by `The only thing I can say here`? You don't have any positive notes whatsoever or any negative notes other the `1E3`? – nick zoum Jan 21 '20 at 12:07
  • Yeah, nothing, really. It's seems like a decent solution but I'm can't process it right now. I'll have to come back after coffee because brain don't work... :/ – VLAZ Jan 21 '20 at 12:09
  • i'm waiting for more opinions anyway ^^ – Marius Jan 21 '20 at 12:14
1

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>
VLAZ
  • 26,331
  • 9
  • 49
  • 67
0
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);
}
Saptarsi
  • 796
  • 5
  • 13