Passare lo stato a una richiamata in JavaScript un uso appropriato delle chiusure?

StackOverflow https://stackoverflow.com/questions/251313

  •  05-07-2019
  •  | 
  •  

Domanda

Supponi di voler fare una richiesta asincrona in JavaScript, ma vuoi passare un po 'di stato al metodo di callback. Il seguente è un uso appropriato delle chiusure in JavaScript?

function getSomethingAsync(someState, callback) {
    var req = abc.createRequestObject(someParams);
    req.invoke(makeCallback(someState, callback));
}

function makeCallback(someState, callback) {
    return function getSomethingCallback(data) {
        var result = processDataUsingState(data, someState);
        callback(result); // alternately/optionally pass someState along to result
    }
}

In caso contrario, esiste un modo migliore o più idiomatico?

È stato utile?

Soluzione

Non vedo alcun problema immediato con questo: le chiusure sono potenti per numerosi motivi, uno dei quali sta eliminando la necessità di utilizzare le variabili globali per il mantenimento dello stato.

Detto questo, l'unica cosa di cui devi essere cauto riguardo alle chiusure sono le perdite di memoria che si verificano in genere in IE, ma di solito sono IIRC, relative agli elementi DOM e ai gestori di eventi ad esse collegati.

Procedere!

Altri suggerimenti

Il modo più idiomatico è usare Function.bind , quindi non è necessario duplicare il codice per creare la chiusura. Userò un semplice esempio (che non ha il tuo codice personalizzato) per spiegare

/**
 * Retrieves the content of a url asyunchronously
 * The callback will be called with one parameter: the html retrieved
 */
function getUrl(url, callback) {
    $.ajax({url: url, success: function(data) {
        callback(data);
    }})    
}

// Now lets' call getUrl twice, specifying the same 
// callback but a different id will be passed to each
function updateHtml(id, html) {
    $('#' + id).html(html);
}


// By calling bind on the callback, updateHTML will be called with 
// the parameters you passed to it, plus the parameters that are used
// when the callback is actually called (inside )
// The first parameter is the context (this) to use, since we don't care,
// I'm passing in window since it's the default context
getUrl('/get/something.html', updateHTML.bind(window, 'node1'));
// results in updateHTML('node1', 'response HTML here') being called
getUrl('/get/something-else.html', updateHTML.bind(window, 'node2'));
// results in updateHTML('node2', 'response HTML here') being called

Function.bind è nuovo, quindi se hai bisogno di supporto all'indietro, guarda la sezione Compatibilità di Function.bind

Infine, so che la domanda non è stata taggata come jQuery. Questo è stato solo il modo più rapido per mostrare una funzione asincrona senza affrontare problemi tra browser

è meglio (più bello) usare funzioni anonime:

function getSomethingAsync (someState, callback) {
    req.invoke (function (data) {
       var result = processDataUsingState (data, someState);
       callback (result);
    });
}

Puoi anche manipolare il valore di " questo " in una funzione con call () / apply ().

Ad esempio, specifica che un ulteriore argomento del tuo metodo asincrono è un oggetto da usare come " questo " nel callback. Questo è il modo in cui jQuery imposta il nodo dom su " questo " nei callback di eventi.

function getSomethingAsync(callback, scope) {
    var req = abc.createRequestObject(someParams);
    req.invoke(function(rsp) {
      callback.apply(scope, [rsp]);
    });
}

// usage:
getSomethingAsync(function() {console.log(this.someState)}, {someState:'value'});
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top