2009-06-21 21 views
1

Ich lief in einem internen Web-Site über diese Schnipsel, aber ich habe Probleme es zu verstehen:Was macht dieser Javascript-Code?

function safeWrap(f) { 
    return function() { 
    setTimeout.apply(window, [f, 0].concat([].slice.call(arguments))); 
    }; 
} 

Später, es wie folgt verwendet wird:

// Set click handler. 
(...).click(safeWrap(function() { ... })); 

Was ist, dies zu tun bedeutete ?

Antwort

11

safeWrap gibt eine Funktion zurück, die beim Aufruf ein Timeout von 0 ms festlegt (Klickereignis ausgelöst).

Wenn die safeWrap-Funktion mehr Argumente als f übergeben wird, fügt sie diese zur Argumentliste der Funktion f hinzu.

Das ist nur Interpretation des bereitgestellten Codes. Ich kann also nicht sagen, wozu es eigentlich gedacht ist ... Wo wird dieser Code zum Beispiel verwendet?

+0

Danke für Ihre Antwort, Ronald. Können Sie näher erläutern, warum ".call" auf ".slice" aufgerufen wird? Ich bin sehr verwirrt über diesen Teil. –

+0

@Kyle, [] .slice.call (Argumente) wird verwendet, um das arguments-Objekt in ein Array-Objekt umzuwandeln. Das arguments-Objekt wird als array-ähnliches Objekt bezeichnet (es hat eine length-Eigenschaft und einige Eigenschaften verwenden die Zahl für ihre Namen). Das Aufrufen von Slice im Kontext von Argumenten macht den Rückgabewert zu einem Array, das diese nummerierten Eigenschaften in Argumenten enthält. –

+0

Die Methode "call" führt die Funktion mit den angegebenen Argumenten aus, sodass Sie ihren Rückgabewert (ein Array) und nicht die Funktionsreferenz erhalten. – Ronald

0

Ein Grund dafür ist, den Click-Handler laufen zu lassen, ohne die Seite einzufrieren. JavaScript ist single threaded. Wenn der Klick-Handler (f) eine lange Zeit benötigt, um ausgeführt zu werden (möglicherweise macht er eine Berechnung, die etwa 1 Minute dauert), sind alle Klicks/Aktionen, die der Benutzer auf dem Bildschirm ausführt, added to a event queue. Der Browser führt diese Aktionen aus, sobald der Click-Handler abgeschlossen ist. Aber bis dahin scheint die App für den Benutzer nicht mehr zu reagieren - er klickt auf Schaltflächen, aber nichts scheint zu passieren.

setTimeout hilft, weil der Click-Handler sofort zurückkehrt. Der Callback f wird zur Ereigniswarteschlange hinzugefügt, um in einem zukünftigen Turn ausgeführt zu werden, was dem Browser die Möglichkeit gibt, alle bereits in der Queue vorhandenen Events auszuführen (z. B. kann die Button-Animation des Herunterdrückens und Wiederkommens eine Chance haben, verarbeitet zu werden) Wenn Sie einen lang laufenden Click-Handler haben, bleibt der Button gedrückt.

Während dies besser ist, gibt es immer noch eine Chance, dass die Seite eingefroren wird, wenn f ausgeführt wird. Der Weg, dies zu vermeiden, würde für f seine Arbeit in kleinen Stücken erledigen, d. H. Etwas für etwa 20 ms tun, und dann setTimeout mit einem Rückruf für den Rest der Arbeit aufrufen. Auf diese Weise haben alle anderen Ereignisse, die sich während dieser 20 ms angesammelt haben, eine Chance zu laufen. Eine solche Funktion könnte wie folgt aussehen:

something.click(safeWrap(function() { 

    function part1() { /* do something */ } 
    function part2() { /* do something */ } 

    part1(); 

    safeWrap(part2); 

})); 

Ein weiterer Grund, dies zu tun wäre, um nicht eine Ausnahme zu lassen, die bis zum Klick-Methode in der Klick-Handler Blase passieren könnte. Vielleicht fängt die Methode click automatisch Ausnahmen ab und zeigt sie auf dem Bildschirm an, und in diesem speziellen Fall möchten wir, dass der Fehler unbemerkt bleibt. Das funktioniert, weil f in einer anderen Runde der Ereignisschleife ausgeführt wird und Ausnahmen nicht den Stapel auf click gehen, da der Aufrufstapel in dem neuen Zug mit f beginnt. Die Ausnahme würde Blase bis zur click Methode, wenn die Prozedur nicht in safeWrap weil in diesem Fall eingewickelt wird, würde f ein regelmäßiger Methodenaufruf sein von click

Schließlich wird angemerkt, dass der Click-Handler auch nach sicherer Verpackung bekommt all die Argumente, die die click-Methode zu ihm übergibt. Es tut nicht erhalten die zusätzlichen Argumente an die safeWrap übergeben, wie in der anderen Antwort hingewiesen. Dies ist offensichtlich sinnvoll, da der Click-Handler nicht darauf achten soll, ob der Handler direkt übergeben oder sicher umschlossen wird.Dieser Code macht es wahrscheinlich klar:

(function() { 
    console.clear(); 

    function safeWrap(f) { 
    return function() { 
     setTimeout.apply(window, [f, 0].concat([].slice.call(arguments))); 
    }; 
    } 

    var f = function(a) { console.log(a /* prints 2 */); throw Error("f"); }; 

    function click(f) { 
    f(2); 
    } 

    click(safeWrap(f, 1)); 

})();