在双循环中添加延迟
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, ' '); //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, ' '); //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);
}
在此代码中(来源: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, ' '); //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, ' '); //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);
}