在双循环中添加延迟

add a delay in a double loop

在此代码中(来源:eloquent javascript)我想为这两个循环中的任何一个添加 1 秒的延迟,但我没有以任何方式进行管理。我想看看如何用 setTimeout 为每个循环和两个循环解决这个问题(每次迭代一个接一个地执行 1 秒,谢谢。我没能从类似的 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);

您可以将生成器与 setinterval 结合使用,每秒调用 iterator#next。所以在下面的例子中,只要你想等 1 秒就做 yield board

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>

我们可以通过 publish-subscribe pattern 的非常简单的实现来拆分您的显示和处理逻辑。我们基本上需要这三个东西

  • 消息队列或消息通道。在这种情况下,我们可以使用数组 - 没有理由不这样做,因为它是最简单的实现方式。
  • 发布者将消息添加到队列中。在这种情况下,您执行的算法每次都会添加 board
  • 将对数组中的每个条目执行某些操作的订阅者。在这种情况下,只需将其打印到控制台即可。
  • 消息代理 - 这通常是将消息发送给订阅者的部分。在这里,我们可以使用一个简单的 setInterval,它会定期轮询消息队列,如果有消息,则会转发它们。

商业发布-订阅系统可能有很多花里胡哨的东西 - 多个 queues/channels、消息过滤、主题、消费事件的存储等。我们真的不需要所有这些对于这种情况,但值得一提的是,以下是发布-订阅系统如何工作的示例,而不是完整的实现。不过,我们不一定需要所有这些来解决这个问题。这是一个基本的实现:

//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)
}

如前所述,这是对其工作原理的概述。请注意,实现更接近 observer 但不会与更改同时发生。有时设计模式可能会模糊彼此之间的界限,特别是取决于它们的使用方式。

无论如何,这种模式的优点是您可以将显示(数据消费)逻辑与计算(数据生产)分离。如果您想为其生成的数据添加不同的消费者,则无需更改您的算法。

我们可以轻松扩展它以包含多个订阅者:

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>

或者这里有一个小变化,您可以在其中添加按不同时间表工作的订阅者:

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>

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);
}