Синхронизация вызовов плагинов на основе событий в JavaScript - PullRequest
1 голос
/ 16 июня 2011

Я пишу некоторый JavaScript, который взаимодействует с плагином браузера (надстройка в FF, ActiveX в IE).Некоторые вызовы являются асинхронными и вызывают событие после завершения.В некоторых случаях мне нужно объединить вызовы в цепочку, но нужно дождаться завершения первого вызова, прежде чем начинать второй.Например:

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

pluginObject.disconnectDevice(deviceKey);
pluginObject.connectDevice(deviceKey, backingInfo);

Просто вызвать их прямо так, как это будет невозможно, потому что соединение инициируется до того, как разъединение действительно завершено, и плагин не может это обработать.

У меня уже настроены слушатели, и я могу сделать что-то вроде:

function handleConnectionChange(connectionState, /* ... */, doReconnect) {
    if (connectionState === state.disconnected && doReconnect) {
        pluginObject.connectDevice(deviceKey, backingInfo);
    }
}

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

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

Обновление: решение Благодаря некоторым указателям из Густаво, я пошел сподход обертывания вызовов плагинов, чтобы заставить их использовать объекты jQuery Deferred:

var connectDevice = function(deviceKey, backingInfo) {
    var deferred = $.Deferred();
    var connectHandler = function(event) {
        // unregister connectHandler
        if (event.connectionState === ERROR) {
            showAlert("Error connecting device", event.message);
            deferred.reject();
        } else {
            showAlert("Device connected", event.message);
             deferred.resolve();
        }
    };

    // register connectHandler
    pluginObject.connectDevice(deviceKey, backingInfo);
    return deferred.promise();
};

Если я создаю подобную оболочку для отключения, теперь я могу связывать вызовы методов (или не в зависимости от потока):

if (forceDisconnect) {
    disconnectDevice(deviceKey).done(connectDevice(deviceKey, backingType));
} else {
    connectDevice(deviceKey, backingType);
}

Я также могу запустить цепочку с помощью connectDevice или добавить другую функцию в поток forceDisconnect и т. Д.

Ответы [ 3 ]

1 голос
/ 16 июня 2011

Почему вы говорите, что Отложенные не соответствуют обратным вызовам?Мне кажется, что

pluginObject.disconnectDevice(deviceKey).then(function() { 
    pluginObject.connectDevice(deviceKey, backingInfo);
});

выглядит довольно естественно.

Если вы не можете изменить код плагина, вы все равно можете использовать этот подход, но, конечно, вам придется обернутьплагин в каком-то API-адаптере.По сути, каждый вызов disconnectDevice в вашей оболочке создаст Deferred, зарегистрирует его в очереди и вернет.Когда вы получаете событие отключения, вы resolve все ожидающие отложенные действия по порядку (будьте осторожны с повторным входом).

Это нужно делать для каждого события, запускаемого плагином, который вы хотите обработать.

Преимущество отложенного подхода заключается в улучшении читабельности кода и возможности сопровождения IMHO (по сравнению с API прослушивателя событий).

0 голосов
/ 16 июня 2011

Предполагая, что вы установили обработчик с помощью простого свойства onConnectionChange, вы можете написать новую функцию, которая вместо этого принимает обратный вызов.

// The new function, it takes a callback to let you know
// that disconnecting is done
pluginObject.disconnect = function (deviceKey, callback) {
     var me = this;
     me.onConnectionChange = function (connectionState) {
        if (connectionState === state.disconnected) {
             delete me.onConnectionChange;
             callback();
        }
}

// Now you can call
pluginObject.disconnect(deviceKey, function() {
    pluginObject.connectDevice(deviceKey, backingInfo);
});
0 голосов
/ 16 июня 2011

Разве вы не можете просто добавить обратный вызов к disconnectDevice и передать вызов на connectDevice?

pluginObject.disconnectDevice = function ( key, callback ) {
    // do stuff and then when disconnect complete...
    callback();
};

... тогда, когда вы хотите подключить устройство ...

pluginObject.disconnectDevice(deviceKey, function() {
    pluginObject.connectDevice(deviceKey, backingInfo);
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...