2016-09-19 54 views
0

我有一种情况,至今我一直无法找到满意的解决方案。以下是高层次的代码。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()查找匹配项,该函数返回布尔值truefalse。如果条件是true,那么我记录数组项目。如果您现在运行代码(https://jsfiddle.net/thdoan/0tubbokj/),您应该看到数字1-3和7-9输出到控制台。

我想要做的是在每个数字之间输出带有一秒延迟的数字。我知道如何在每个循环迭代之间引入延迟,但我只想为打印的数字添加延迟(即当matched()返回true时)。

澄清:我目前的解决方案,我不满意,是将匹配的项目保存到一个单独的数组,并在延迟迭代该数组,但我正在寻找一种解决方案,不需要创建一个新的数组。

+0

您需要为递归。使用递归函数更改循环for()。如果你不能,你可以'setTimeout(function(){console.log(result);},1000);'但它不好。 –

+0

@MarcosPérezGude可以在小提琴或codepen中演示您的解决方案,因为我无法使其工作。谢谢。 – 10basetom

+0

我的建议等于TJCrowder的答案。 –

回答

3

我想要做的是与输出中的每个数字之间的一秒钟的延迟数。

你也评论说:

...在真正的应用程序匹配的集合可能会变得非常大,所以如果有一个我宁愿不占用更多的内存解决方案不需要输出到第三个阵列。

为了同时实现这些目标,你必须完全放弃你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; 
 
}

其实,这似乎更清洁,我反正,即使没有深筹码的关注。

+1

看起来这是OP想要的。在功能上,这是最好的答案:D +1 – Cerbrus

+1

T.J Crowder我喜欢你的解决方案,它对我来说看起来很优雅。非常感谢! – 10basetom

+0

@ 10basetom:它的缺点是它必须在'o'中构建和保存这个键的数组,你说这可能是成千上万的。也就是说,数组中的“数千”字符串在现代JavaScript环境中并不是什么大问题,您可以在完成时释放数组。另一种方法是每次在'for-in'循环中计数到现在的“j”,A)会有更高的运行时间成本(虽然不太可能足够大以至于B)依靠稳定的'for-in'迭代顺序。 *(续)* –

2

的解决方法是比较简单的:

不要担心,当你收集结果的记录。相反,将全部结果存储在新阵列中。

然后遍历该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. 
 
    } 
 
})();

+0

Cerbrus,谢谢,但那是我不满意的解决方案:)。示例代码中的数组非常简单,但在真实应用程序中,匹配的集合可能变得非常大,所以如果存在不需要输出到第三个数组的解决方案,我宁可不消耗更多的内存。 – 10basetom

+0

我们在说什么_“非常大”_10basetom? – Cerbrus

+0

Cerbrus,在o中有数千个物品,在a中有数百个物品。可能有数百个匹配项,每个匹配项可能是一个大对象,所以我试图尽可能地减少内存消耗。 – 10basetom

1

带你的代码,但改变输出到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(); 
1

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

+0

如果有10000个匹配项,则有10000个超时同时处于待处理状态。这种方法可能是更大阵列的内存消耗。 – Cerbrus

+0

@Cerbrus,对。现在用setInterval。 –

+0

使用'Set'应该包含兼容性免责声明。即使它只会被调用一次,你仍然在调用'setInterval' _。 – Cerbrus

-1

可以创建一个功能,其中包括电流forfor..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); 
 
});

+0

您可能会同时产生数千个承诺,每个承诺都有一个待处理的超时。这将是一个记忆猪。 – Cerbrus