2016-09-19 5 views
0

Ich habe eine Situation, die ich bisher keine befriedigende Lösung für gefunden habe. Unten ist der Code auf hoher Ebene.JavaScript Verzögerung, wenn in der inneren Schleife

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

Ich habe ein Array und ein Objekt. Ich durchlaufe das Array und dann das Objekt, um über die Funktion matched() eine Übereinstimmung zu finden, die einen booleschen Wert true oder false zurückgibt. Wenn die Bedingung true ist, protokolliere ich das Array-Element. Wenn Sie jetzt den Code ausführen (https://jsfiddle.net/thdoan/0tubbokj/), sollten Sie die Nummern 1-3 und 7-9 auf der Konsole ausgeben sehen.

Ich versuche, die Zahlen mit einer Verzögerung von einer Sekunde zwischen jeder Zahl auszugeben. Ich weiß, wie man eine Verzögerung zwischen jeder Schleifeniteration einführt, aber ich möchte nur die Verzögerung für die Zahlen hinzufügen, die gedruckt werden (d. H. Wenn matched()true zurückgibt).

Erläuterung: Meine aktuelle Lösung, mit der ich nicht zufrieden bin, besteht darin, die übereinstimmenden Elemente in einem separaten Array zu speichern und mit einer Verzögerung über dieses Array zu iterieren, aber ich suche nach einer Lösung, die dies nicht tut erfordert das Erstellen eines neuen Arrays.

+0

Sie benötigen Rekursion dafür. Ändern Sie die Schleife 'for()' mit einer rekursiven Funktion. Wenn Sie nicht können, können Sie 'setTimeout (function() {console.log (Ergebnis);}, 1000);' aber es ist nicht in Ordnung. –

+0

@ MarcosPérezGude können Sie Ihre Lösung in einer Geige oder Codepen demonstrieren, weil ich es nicht zum Laufen bringen konnte. Vielen Dank. – 10basetom

+0

Mein Vorschlag entspricht der Antwort von TJCrowder. –

Antwort

3

Was ich versuche zwischen jeder Zahl in den Zahlen mit einer Verzögerung von einer Sekunde ist die Ausgabe zu tun.

Sie haben auch gesagt, in einem Kommentar:

... in der realen Anwendung der abgestimmten Satz wachsen kann sehr groß sein, würde ich so etwas nicht mehr Speicher verbrauchen, wenn es eine ist Lösung, die keine Ausgabe an ein drittes Array erfordert.

diese beiden Ziele zu erreichen, müssen Sie vollständig Ihre for Schleifen verzichten und stattdessen eine verkettete Reihe von setTimeout s zu tun.

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

HINWEIS: Wenn kann es Tausende von Nicht-Spielen in Folge sein, könnten Sie in tick statt, um es mit einer Schleife betrachten Verkettungstag. Ab ES2015 sollte JavaScript eine Tail-Call-Optimierung haben und unsere tick müsste sich nicht auf den Stack schieben (es würde nur an den Anfang zurückrufen), aber einige JavaScript-Engines haben TCO noch nicht implementiert, was könnte meinen Sie würden mit einer signifikanten Stapeltiefe enden.

Also, mit einer Schleife:

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

Eigentlich ohnehin sauberer mir scheint, auch ohne den Deep Stack Sorge.

+1

Sieht so aus, als ob das OP dies wünscht.Funktional ist dies die beste Antwort: D +1 – Cerbrus

+1

T.J Crowder Ich mag deine Lösung, es scheint mir elegant. Danke vielmals! – 10basetom

+0

@ 10basetom: Der Nachteil ist, dass es das Array der Schlüssel in "o" bauen und behalten muss, von dem Sie sagten, dass es in den Tausenden sein könnte. Das heißt, "Tausende" von Strings in einem Array sind in modernen JavaScript-Umgebungen keine große Sache, und Sie können das Array freigeben, wenn Sie fertig sind. Die Alternative wäre, den Weg zum aktuellen "j" jedes Mal in einer 'for-in'-Schleife zu zählen, wobei A) höhere Laufzeitkosten hätte (obwohl es wahrscheinlich nicht groß genug ist, um wirklich von Bedeutung zu sein) und B) verlassen sich auf eine stabile "for-in" Iterationsreihenfolge. * (Fortsetzung) * –

2

Die Lösung ist relativ einfach:

Sorgen Sie sich nicht um die Protokollierung, wenn Sie die Ergebnisse sind zu sammeln. Stattdessen speichern alle Ergebnisse in einem neuen Array.

Dann iterieren dass result Array mit einer Verzögerung:

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, danke, aber das war die Lösung, mit der ich nicht zufrieden war :). Das Array im Beispielcode ist sehr einfach, aber in der echten App kann das Matched-Set sehr groß werden. Daher würde ich lieber keinen Speicher mehr verbrauchen, wenn es eine Lösung gibt, die nicht an ein drittes Array ausgegeben werden muss. – 10basetom

+0

Wie _ "sehr groß" _ reden wir, @ 10basetom? – Cerbrus

+0

Cerbrus, bis zu Tausenden von Artikeln in "O" und Hunderten von Artikeln in "A". Es könnte möglicherweise Hunderte von Übereinstimmungen geben und jede Übereinstimmung kann ein großes Objekt sein. Daher versuche ich, den Speicherverbrauch so gering wie möglich zu halten. – 10basetom

1

Ihnen Code nehmen, aber die Ausgabe in ein push in einer anderen (global) Array ändern. Verwenden Sie dann einen Timer, um den Array-Inhalt einzeln zu drucken.

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

Eine ES6-Lösung mit 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

Wenn 10000 Übereinstimmungen vorhanden sind, sind gleichzeitig 10000 Zeitüberschreitungen ausstehend. Diese Methode könnte ein Speicher für größere Arrays sein. – Cerbrus

+0

@ Cerbrus, rechts. jetzt mit setInterval. –

+0

Die Verwendung von 'Set' sollte einen Kompatibilitätshinweis enthalten. Sie rufen auch noch 'setInterval' _in einer Schleife_ auf, obwohl sie nur einmal aufgerufen wird (sollte). – Cerbrus

-1

Sie können eine Funktion erzeugen, die aktuellen for umfasst, for..in Schleifenmuster, obwohl nur einzelne Iterieren a Element an for Schleife eine Anruffunktion unter Beibehaltung bestehender for..in Schleife; Ersatz, der eine Promise zurückgibt, die die Funktion rekursiv aufruft, wenn die inkrementierte Variable kleiner als a.length ist; sonst rekursiv Funktion mit inkrementierter Variable zurückgeben, oder wenn Variable a.length ist, gebe einen Wert an am Ende des Prozesses zurück.

wird dieser Ansatz Anrufe setTimeout() sequentiell, macht ohne einen anstehenden Anruf zu setTimeout in Zukunft nächster Aufruf Funktion besteht nur zu erzeugen, wenn Strom setTimeout abgeschlossen ist, oder keine Übereinstimmung für diese Iteration von Schleifen zurückgegeben.

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

Sie generieren möglicherweise Tausende von Versprechen gleichzeitig mit jeweils einem ausstehenden Timeout. Das wird ein Gedächtnisschwein sein. – Cerbrus

Verwandte Themen