在JavaScript中同步基于事件的插件调用
Synchronizing event-based plugin calls in JavaScript
我正在编写一些与浏览器插件(Firefox中的插件,IE中的ActiveX)交互的JavaScript。有些调用是异步的,并在完成时触发事件。在某些情况下,我需要将调用链接在一起,但需要等待第一个调用完成后再启动第二个调用。例如:
连接设备的呼叫需要首先检查设备是否已经连接,然后断开连接。因此,呼叫将是:
pluginObject.disconnectDevice(deviceKey);
pluginObject.connectDevice(deviceKey, backingInfo);
像这样直接调用它们会失败,因为在断开连接真正完成之前就启动了连接,而插件无法处理这一问题。
我已经设置好了听众,我可以做一些类似的事情:
function handleConnectionChange(connectionState, /* ... */, doReconnect) {
if (connectionState === state.disconnected && doReconnect) {
pluginObject.connectDevice(deviceKey, backingInfo);
}
}
但我实际上想要一种更通用的方法——一种即使使用不同的连锁事件集也能重复使用的方法。在这个特殊的例子中,这很简单,但即使这样也有点草率。我在连接事件处理程序中添加了重新连接信息逻辑,这样做很容易看到条件链接失控。
有没有处理这种工作流的库?我查看了jQuery的延迟内容,它有我想要的链接,但它似乎真的不适合回调。Sproutcore的StateCharts看起来很有趣,但似乎也没有能力重新处理已经异步的流。
更新:解决方案多亏了Gustavo的一些指针,我采用了包装插件调用的方法,使它们能够利用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流添加另一个功能,等等。
为什么说Deferred不适合回调?在我看来
pluginObject.disconnectDevice(deviceKey).then(function() {
pluginObject.connectDevice(deviceKey, backingInfo);
});
读起来很自然。
如果你不能更改插件代码,你仍然可以使用这种方法,但当然你必须将插件包装在某种API适配器中。基本上,包装器中对disconnectDevice
的每次调用都会创建一个Deferred
,将其注册到队列中并返回。当您收到断开连接事件时,您会按顺序resolve
所有挂起的延迟(注意重新进入)。
你需要为你想要处理的插件触发的每个事件做这件事。
延迟方法的优点是改进了代码可读性和可维护性IMHO(优于事件侦听器API)。
难道不能给disconnectDevice
添加一个回调并将调用传递给connectDevice
吗?
pluginObject.disconnectDevice = function ( key, callback ) {
// do stuff and then when disconnect complete...
callback();
};
然后当你想连接一个设备。。。
pluginObject.disconnectDevice(deviceKey, function() {
pluginObject.connectDevice(deviceKey, backingInfo);
});
假设使用名为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);
});
- 如何在elfinder插件(一个文件管理器插件)上获得上传前事件
- 在插件中分配事件
- JQuery facebook订阅插件鼠标事件
- CSS + jQ插件阻止AJAX调用/事件侦听器工作
- 使用所选插件更改动态添加的选择上的事件
- 有没有一种方法可以重新绑定jQuery插件中引用的事件处理程序
- 自定义jQuery插件:事件未按预期运行
- Jquery插件绑定更改事件
- 如何使用show hint插件在CodeMirror中订阅选择事件
- 在第三次onPageClick事件后,使用twbspagination插件和AJAX更新JS分页
- jQuery有没有,或者有没有jQuery插件,内置了监听CSS3动画事件的功能(例如animationEnd)
- jQuery插件的自定义事件与回调
- 可以't在我的Firefox插件中触发点击事件
- 如何在我的自定义插件中绑定调整大小事件
- 如何将自定义事件添加到 jQuery 插件模式中
- 如何从jQuery插件中附加keyup事件
- 火狐插件 - 无法触发任何类型的点击事件
- Firefox 引导插件:安装事件未执行
- 了解JavaScript事件并应用jQuery事件/插件
- 是否有一个移动触摸事件插件的jQuery