Передача состояния к обратному вызову в JavaScript, соответствующее использование замыканий? - PullRequest
2 голосов
/ 30 октября 2008

Предположим, вы хотите сделать асинхронный запрос в JavaScript, но хотите передать некоторое состояние методу обратного вызова. Является ли следующее уместным использование замыканий в 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
    }
}

Если нет, есть ли лучший или более идиоматический способ?

Ответы [ 4 ]

2 голосов
/ 30 октября 2008

Я не вижу никаких непосредственных проблем с этим - замыкания являются мощными по многим причинам, одна из которых устраняет необходимость использования глобальных переменных для поддержания состояния.

Тем не менее, единственное, что вам нужно с осторожностью относиться к замыканиям, - это утечки памяти, которые обычно происходят в IE, но обычно они связаны с элементами DOM и обработчиками событий, прикрепленными к ним.

Действуйте!

1 голос
/ 19 января 2012

Более простой способ - использовать Function.bind, тогда вам не нужно дублировать код для создания замыкания. Я буду использовать простой пример (в котором нет вашего пользовательского кода), чтобы объяснить

/**
 * 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 является новым, так что если вам нужна обратная поддержка, посмотрите раздел Совместимость Function.bind

Наконец, я знаю, что вопрос не был помечен как jQuery. Это был самый быстрый способ показать асинхронную функцию, не сталкиваясь с кросс-браузерными проблемами

0 голосов
/ 23 января 2012

Вы также можете манипулировать значением this в функции с помощью call () / apply ().

Например, укажите, что дополнительным аргументом вашего асинхронного метода является объект, который будет использоваться как "this" в обратном вызове. Вот как jQuery устанавливает для узла dom значение «this» в обратных вызовах событий.

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'});
0 голосов
/ 30 октября 2008

лучше (лучше) использовать анонимные функции:

function getSomethingAsync (someState, callback) {
    req.invoke (function (data) {
       var result = processDataUsingState (data, someState);
       callback (result);
    });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...