vorrebbe aiutare a capire la funzione di acceleratore javascript

4

Un utente su Stack Overflow ha pubblicato una domanda relativa alla sovrascrittura di una funzione JS nativa. La domanda è qui e questo è il codice:

function throttle(fn, time) {
  var handle;

  var execute = function() {
    handle = null;
    fn.apply(this, arguments);
  };

  var throttled = function() {
    if(!handle) {
      handle = setTimeout(execute.bind(this), time);
    }
  };

  throttled.toString = function() {
    return fn.toString() + "\n// throttled to " + time + "ms";
  };

  return throttled;
}

var makeAjax = throttle(function(callback) {
  $.getJSON("/path", callback);
}, 500);

Ho una buona padronanza (credo) su JavaScript, ma ci sono alcune aree che rimangono molto grigie per me. Mi piacerebbe sapere cosa sta succedendo in questo codice?

Non capisco cosa facciano bind e apply , o quale sarebbe il risultato finale di tutto questo. Ho cercato bind e apply sulla documentazione JS di Mozilla, ma la definizione "ufficiale" ha fatto ben poco per aiutarmi a capire cosa stanno facendo in questo contesto.

Apprezzo il tuo aiuto!

    
posta jwatts1980 11.01.2013 - 20:27
fonte

2 risposte

1

Ho trovato anche abbastanza difficile leggere, il codice di giocoleria di contesto è in generale difficile da leggere e quindi soggetto a errori.

this in JavaScript spesso si riferisce al genitore della funzione, cioè quando una funzione è memorizzata come campo di un oggetto come:

function fun(){
    return this
}
obj = {f:fun}

Chiamando obj.f() restituirà obj , semplicemente chiamando fun() tuttavia restituirà l'elemento window in quanto la funzione non viene chiamata come membro, quindi il valore di this dipende dal contesto. Quando si crea un wrapper come quello che mostri invariabilmente il contesto per this , i metodi bind e apply vengono creati per gestire situazioni del genere. fun.bind(cont) creerà una versione di fun dove this è sempre cont . fun.apply(cont,args) eseguirà fun con this impostato su cont e i valori nella matrice args come parametri.

Il codice in questione mostra come queste cose convolute si ottengono non riuscendo a passare gli argomenti dati alla funzione. I parametri reali vengono passati a throttled , ma l'array arguments che viene utilizzato proviene da execute , è vuoto.

L'uso della funzione bind non è necessaria, this potrebbe anche essere memorizzato in una variabile semplice.

Ecco una versione fissa e, a mio avviso, più semplice da leggere, insieme a un codice che dimostra la funzionalità:

function throttle(fn, time) {
    var handle;
    function throttled() {
        var args;
        var context;
        if(!handle) {
            args = arguments;
            context = this;
            handle = setTimeout(execute, time);
        }

        function execute() {
            handle = null;
            fn.apply(context, args);
        };
    };

    throttled.toString = function() {
        return fn.toString() + "\n// throttled to " + time + "ms";
    };

    return throttled;
}

obj = {
    toString:function(){
        return "obj's toString";
    }
    ,f:throttle(function(input){
        console.log(input+", "+this);
    },1000)
}
obj.f("input string 1")
obj.f("input string 2")
obj.f("input string 3")
obj.f("input string 4")
    
risposta data 13.01.2013 - 15:56
fonte
4

In realtà è piuttosto semplice: l'handle di una chiamata setTimeout viene utilizzato come protezione contro più esecuzioni.

La variabile con limitazione contiene una funzione che è anche il valore di ritorno - makeAjax conterrà quella funzione. Quando viene eseguito, sarà

  1. Causa la funzione execute da chiamare dopo un ritardo, se l'handle è stato cancellato / non già impostato

  2. Ritorna immediatamente altrimenti.

Questo rende il nome della funzione apparente - limita l'esecuzione della funzione di input a dopo un certo tempo e non più di una volta contemporaneamente.

Utilizza bind per impostare il contesto this della funzione memorizzata nella variabile di esecuzione .

La variabile di esecuzione è una funzione che racchiude il richiamo della funzione di input con la cancellazione dell'impugnatura, in modo tale che ogni volta che viene richiamata la funzione memorizzata in execute , consente ulteriori esecuzioni della funzione. La funzione uses si applica per eseguire la funzione con un contesto e argomenti specifici.

Spero che chiarisca qualcosa - ho trovato difficile esprimere a parole, e non sono sicuro di averlo gestito in modo chiaro e conciso.

    
risposta data 12.01.2013 - 11:05
fonte

Leggi altre domande sui tag