2009-06-21 13 views
1

je suis tombé sur cet extrait dans un site Web interne, mais je vais avoir du mal à comprendre:Que fait ce code Javascript?

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

Plus tard, il est utilisé comme ceci:

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

Qu'est-ce que cela signifie faire ? SafeWrap renvoie une fonction qui définit un délai d'expiration de 0 ms lors de l'appel (cliquez sur événement déclenché).

Répondre

11

Si la fonction safeWrap reçoit plus d'arguments que f, elle les ajoute à la liste d'arguments de la fonction f.

C'est juste l'interprétation du code fourni. Donc, je ne peux pas dire ce qu'il est vraiment censé faire ... Où ce code est-il utilisé, par exemple?

+0

Merci pour votre réponse, Ronald. Pouvez-vous élaborer un peu sur la raison pour laquelle ".call" est invoqué sur ".slice"? Je suis très confus à propos de cette partie. –

+0

@Kyle, [] .slice.call (arguments) est utilisé pour transformer l'objet arguments en un objet tableau. L'objet arguments est dit être un objet de type tableau (il a une propriété length et certaines propriétés utilisent un nombre pour leurs noms). L'appel de la tranche dans le contexte des arguments fait de la valeur de retour un tableau contenant les propriétés numérotées dans les arguments. –

+0

La méthode "call" exécute la fonction avec les arguments spécifiés, donc vous obtenez sa valeur de retour (un tableau) et non la référence de la fonction. – Ronald

0

L'une des raisons pour lesquelles le gestionnaire de clic s'exécute sans geler la page est la suivante:. JavaScript est un seul thread. Ainsi, si le gestionnaire de clic (f) prend beaucoup de temps à s'exécuter (s'il effectue un calcul qui prend 1 minute), les clics/actions que cet utilisateur effectue sur l'écran sont added to a event queue. Le navigateur effectuera ces actions une fois le gestionnaire de clic terminé. Mais jusque-là, l'application semblera ne pas répondre à l'utilisateur - il clique sur les boutons, mais rien ne semble arriver. Cela aide car le gestionnaire de clic revient immédiatement. Le rappel f est ajouté à la file d'attente des événements pour s'exécuter lors d'un prochain tour, ce qui permet au navigateur d'exécuter tous les événements déjà présents dans la file d'attente (p. Ex. Si vous avez un long gestionnaire de clics, le bouton restera enfoncé.

Bien que ce soit mieux, il y a encore une chance que la page serait gelé quand f ne se exécution. La façon d'éviter cela serait de faire son travail en petits morceaux, c'est-à-dire de faire quelque chose pendant 20 ms, puis d'appeler setTimeout avec un rappel pour le reste du travail. De cette façon, tous les autres événements qui se sont accumulés pendant ces 20 ms auraient une chance de courir. Une telle fonction pourrait se présenter comme suit:

something.click(safeWrap(function() { 

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

    part1(); 

    safeWrap(part2); 

})); 

Une autre raison de le faire serait de ne pas laisser une exception qui pourrait se produire dans la bulle de gestionnaire de clic jusqu'à la méthode de clic. Peut-être, la méthode click attrape automatiquement les exceptions et les affiche à l'écran, et dans ce cas particulier, nous voulons que l'erreur passe inaperçue. Cela fonctionne car f s'exécute sur un tour différent de la boucle d'événements, et les exceptions ne remonteront pas la pile à click car la pile d'appel commence par f dans le nouveau tour. L'exception serait bulle jusqu'à la méthode click si le gestionnaire n'est pas enveloppé dans safeWrap parce que dans ce cas, f serait un appel régulier de la méthode de click

Enfin, notez que le gestionnaire de clic, même après emballage sûr obtient tout les arguments que la méthode click lui passe. Il ne pas obtenir les arguments supplémentaires passés à la safeWrap comme indiqué dans l'autre réponse. Cela est évidemment logique car nous voulons que le gestionnaire de clic ne se soucie pas de savoir si le gestionnaire est transmis directement ou s'il est emballé en toute sécurité.Ce code est probablement clair:

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

})(); 
Questions connexes