JavaScript内部循环中的延迟时间为
我有一种情况,至今我一直无法找到满意的解决方案。以下是高层次的代码。JavaScript内部循环中的延迟时间为
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9],
o = {a:1, b:2, c:3, d:10, e:11, f:12, g:7, h:8, i:9};
function matched(i, j) {
return a[i]===o[j];
}
for (var i=0; i<a.length; ++i) {
for (var j in o) {
if (matched(i, j)) console.log(a[i]);
}
}
我有一个数组和一个对象。我循环访问数组,然后是对象,通过函数matched()
查找匹配项,该函数返回布尔值true
或false
。如果条件是true
,那么我记录数组项目。如果您现在运行代码(https://jsfiddle.net/thdoan/0tubbokj/),您应该看到数字1-3和7-9输出到控制台。
我想要做的是在每个数字之间输出带有一秒延迟的数字。我知道如何在每个循环迭代之间引入延迟,但我只想为打印的数字添加延迟(即当matched()
返回true
时)。
澄清:我目前的解决方案,我不满意,是将匹配的项目保存到一个单独的数组,并在延迟迭代该数组,但我正在寻找一种解决方案,不需要创建一个新的数组。
我想要做的是与输出中的每个数字之间的一秒钟的延迟数。
你也评论说:
...在真正的应用程序匹配的集合可能会变得非常大,所以如果有一个我宁愿不占用更多的内存解决方案不需要输出到第三个阵列。
为了同时实现这些目标,你必须完全放弃你for
循环,而是做一个链接一系列setTimeout
秒。
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9],
o = {a:1, b:2, c:3, d:10, e:11, f:12, g:7, h:8, i:9};
function matched(i, j) {
return a[i]===o[j];
}
// Get the property names in `o`, and start at the beginning
var keys = Object.keys(o);
var i = 0;
var keyIndex = 0;
tick();
function tick() {
// Get the "j" value for this tick
var j = keys[keyIndex];
// Is this a match?
var flag = matched(i, j);
if (flag) {
console.log(a[i]);
}
// Move to the next entry in our nested loops
if (++keyIndex >= keys.length) {
keyIndex = 0;
if (++i >= a.length) {
// Done
return;
}
}
// Continue
if (flag) {
// We output one, wait a second before next
setTimeout(tick, 1000);
} else {
// No output, continue immediately
tick(); // SEE NOTE BELOW
}
}
注:如果可能有数以千计的非匹配的排成一列,你可能会考虑在tick
使用一个循环,而不是链接到它。从ES2015开始,JavaScript应该具有尾部呼叫优化功能,我们的tick
不必将自己推入堆栈(它只会回传到开头),但是一些JavaScript引擎尚未实现TCO,这可能会意味着你会得到一个显着的堆栈深度。
所以,用一个循环:
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9],
o = {a:1, b:2, c:3, d:10, e:11, f:12, g:7, h:8, i:9};
function matched(i, j) {
return a[i]===o[j];
}
// Get the property names in `o`, and start at the beginning
var keys = Object.keys(o);
var i = 0;
var keyIndex = 0;
tick();
function tick() {
var match = findNextMatch();
if (match) {
console.log(match);
setTimeout(tick, 1000);
}
}
function findNextMatch() {
var j;
var match;
while (!match && i < a.length) {
j = keys[keyIndex];
if (matched(i, j)) {
match = a[i];
}
// Move to the next entry in our nested loops
if (++keyIndex >= keys.length) {
keyIndex = 0;
++i;
}
}
return match;
}
其实,这似乎更清洁,我反正,即使没有深筹码的关注。
的解决方法是比较简单的:
不要担心,当你收集结果的记录。相反,将全部结果存储在新阵列中。
然后遍历该result
阵列,具有延迟:
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9],
o = {a:1, b:2, c:3, d:10, e:11, f:12, g:7, h:8, i:9},
result = [];
function matched(i, j) {
return a[i]===o[j];
}
for (var i=0; i<a.length; ++i) {
for (var j in o) {
if (matched(i, j))
result.push(a[i]); // Store the found result.
}
}
var i = 0,
length = result.length;
(function iterator() {
console.log(result[i]); // Log the current result
if(++i < length) { // If there are more entries in the array
setTimeout(iterator, 1000); // Log the next entry in 1 second.
}
})();
带你的代码,但改变输出到push
到另一个(全球)阵列。然后使用计时器逐个打印数组内容。
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9],
o = {a:1, b:2, c:3, d:10, e:11, f:12, g:7, h:8, i:9},
t = [];
function matched(i, j) {
return a[i]===o[j];
}
// function to output first element of array
function output(){
if(t.length > 0){ // only generate output if array t isn't empty
console.log(t.shift());
setTimeout(output, 1000); // recall this function after 1s
}
}
for (var i=0; i<a.length; ++i) {
for (var j in o) {
if (matched(i, j)) t.push(a[i]); // store all found items inside the new array
}
}
output();
ES6解决方案,其中generator。
function* getCommon(array, object) {
var set = new Set(array), k;
for (k in o) {
if (set.has(o[k])) {
yield o[k];
}
};
}
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9],
o = { a: 1, b: 2, c: 3, d: 10, e: 11, f: 12, g: 7, h: 8, i: 9 },
generator = getCommon(a, o),
interval = setInterval(function() {
var item = generator.next();
if (item.done) {
clearInterval(interval);
} else {
console.log(item.value);
}
}, 1000);
可以创建一个功能,其中包括电流for
,for..in
环形图案,虽然仅迭代单a
元件在for
循环函数调用,同时保持现有for..in
回路;替代返回Promise
递归调用函数,如果递增变量小于a.length
;否则用递增变量递归地返回函数,或者如果变量是a.length
,则在完成处理时返回值为.then()
。
这种做法将使呼叫setTimeout()
连续的,没有产生在未来setTimeout
一个等待受理,以函数下次调用仅仅是由当前setTimeout
完成时,或归还for循环的该迭代不匹配。
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
, o = {a: 1, b: 2, c: 3, d: 10, e: 11, f: 12, g: 7, h: 8, i:9};
function matched(i, j) {
return a[i] === o[j];
}
function matcher(index = 0) {
var len = index < a.length;
for (var i = index; i < index + 1; ++i) {
for (var j in o) {
if (matched(i, j)) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(a[i]);
}, 1000)
})
.then(function(result) {
console.log(`result:${result}`);
if (len) {
return matcher(++index)
}
});
}
}
};
return len ? matcher(++index) : "matcher complete";
}
matcher().then(function(complete) {
console.log(complete);
});
您可能会同时产生数千个承诺,每个承诺都有一个待处理的超时。这将是一个记忆猪。 – Cerbrus
您需要为递归。使用递归函数更改循环for()。如果你不能,你可以'setTimeout(function(){console.log(result);},1000);'但它不好。 –
@MarcosPérezGude可以在小提琴或codepen中演示您的解决方案,因为我无法使其工作。谢谢。 – 10basetom
我的建议等于TJCrowder的答案。 –