Javascript Firefox扩展(SDK)中的内容脚本添加事件侦听器
我的Firefox扩展提供了一个JavaScript函数,网站可以使用该函数访问插件功能。网站调用此函数并提供两个回调 网站代码:Javascript Firefox扩展(SDK)中的内容脚本添加事件侦听器,javascript,firefox,firefox-addon,firefox-addon-sdk,Javascript,Firefox,Firefox Addon,Firefox Addon Sdk,我的Firefox扩展提供了一个JavaScript函数,网站可以使用该函数访问插件功能。网站调用此函数并提供两个回调 网站代码: function onButtonClick() { var callbackSuccess = function() { alert("Yeah!"); }; var callbackError = function() { alert("Oh no!"); }; if (window.magicAddon) { // Check if my addo
function onButtonClick() {
var callbackSuccess = function() { alert("Yeah!"); };
var callbackError = function() { alert("Oh no!"); };
if (window.magicAddon) { // Check if my addon is installed
magicAddon.doStuff(callbackSuccess, callbackError);
}
}
unsafeWindow.magicAddon = {
doStuff: function(callbackSuccess, callbackError) {
// Bind the two callbacks to events. The addon will fire one of them
self.port.on("doStuffSuccess", callbackSuccess);
self.port.on("doStuffError", callbackError);
// Fire the event that lets the addon do stuff
self.port.emit("doStuff");
}
};
内容脚本:
function onButtonClick() {
var callbackSuccess = function() { alert("Yeah!"); };
var callbackError = function() { alert("Oh no!"); };
if (window.magicAddon) { // Check if my addon is installed
magicAddon.doStuff(callbackSuccess, callbackError);
}
}
unsafeWindow.magicAddon = {
doStuff: function(callbackSuccess, callbackError) {
// Bind the two callbacks to events. The addon will fire one of them
self.port.on("doStuffSuccess", callbackSuccess);
self.port.on("doStuffError", callbackError);
// Fire the event that lets the addon do stuff
self.port.emit("doStuff");
}
};
这在第一次调用时效果很好,但下一次网站调用doStuff()时,新的侦听器会累加起来,并执行两次alert()。下次有三个警报,以此类推
你知道如何优雅地避免听众加起来吗?我可以完全清除事件类型吗?
到目前为止不起作用的是:
- 改为使用
,因为我有两个回调事件:只有一个回调事件被清除,另一个回调事件保留并与下一个回调事件相加self.port.once(…)
- 在注册新的侦听器之前,请使用
删除旧的侦听器,因为我没有旧的回调引用self.port.removeListener
问题似乎与类似,只是他使用了一个回调侦听器,因此可以使用
self.port.once(..)
您可以使用self.port.once
然后手动删除另一个回调:
doStuff: function(callbackSuccess, callbackError) {
// Bind the two callbacks to events. The addon will fire one of them
self.port.once("doStuffSuccess", function() {
callbackSuccess();
self.port.removeListener(callbackError);
});
self.port.once("doStuffError", function() {
callbackError();
self.port.removeListener(callbackSuccess);
});
// Fire the event that lets the addon do stuff
self.port.emit("doStuff");
}
您处于内容脚本中,因此无法完全清除事件类型,只能在主附加代码中使用低级API进行清除
但是,我建议避免使用unsafeWindow
来提供这种功能,因为它是不安全的。如果您保持API异步,您可以使用内容脚本和页面之间的postMessage
管道来执行相同的操作;并提供了一个单独的javascript文件,人们可以将其包含在他们的网站中,您可以在其中公开postMessages调用的抽象(例如,magicAddon.doStuff()
)。如果您愿意,您还可以在网站中自动从附加组件中插入该脚本
处理这个机制肯定有点复杂,但是可以避免使用unsafeWindow
您可以找到有关内容脚本通信的更多信息
希望有帮助
更新:要回答您的评论,您需要一个变量来跟踪doStuff
调用活动:
doStuff: function() {
var executing = false;
return function(callbackSuccess, callbackError) {
if (executing)
return;
executing = true;
// Bind the two callbacks to events. The addon will fire one of them
self.port.once("doStuffSuccess", function() {
executing = false;
callbackSuccess();
self.port.removeListener(callbackError);
});
self.port.once("doStuffError", function() {
executing = false;
callbackError();
self.port.removeListener(callbackSuccess);
});
// Fire the event that lets the addon do stuff
self.port.emit("doStuff");
}
}()
注意末尾的()
。基本上,在doStuff
末尾设置的函数是我们最初分配的函数的结果。
通过这种方式,我们为doStuff
方法创建一个闭包,其中一个正在执行的变量处于活动状态,如果已经有doStuff
执行或没有执行,则保持跟踪,以丢弃任何其他doStuff
调用,直到完成为止
注意:即使在这种情况下javascript不需要,也可以将该函数封装在括号中,以确定该函数是“自动执行的”:`doStuff:(function(){…}())
您也可以使用该代码的对象属性> MAGICADON < /代码>,但是在这种情况下,它将被暴露。 < P>您必须考虑在调用第一次调用之前,网站可能再次调用<代码> MAGICADON.DOSCODE()/代码>。因此,在任何时间点都可能有多个调用在执行——您应该确保调用正确的侦听器。此外,如果任何一个回调触发,您都需要删除这两个侦听器,否则您将泄漏内存。以下是这一方法的工作原理:
doStuff:function(callbackSuccess,callbackError){
//生成随机呼叫ID
var callID=Math.random();
//将两个回调绑定到事件。确保仅对具有
//右键呼叫ID。
函数onSuccess(id){
if(id==callID){
callbackSuccess();
RemovelListeners();
}
}
函数onError(id){
if(id==callID){
callbackError();
RemovelListeners();
}
}
函数RemovelListeners(){
self.port.removeListener(“dostuffsucture”,onSuccess);
self.port.removeListener(“dostufferro”,onError);
};
self.port.on(“dostuffsucture”,onSuccess);
self.port.on(“dostufferro”,onError);
//触发允许插件执行操作的事件
self.port.emit(“doStuff”,callID);
}
这使用随机调用ID来识别调用-代码处理doStuff
事件获取调用ID作为参数,需要在dostuffsucture
或dostuferror
事件中将其发送回,以确保调用了正确的回调。是的,unsafeWindow
是不安全的,我已阅读,但是document.body.appendChild(script)
对我来说似乎并没有太好…谢谢,这是一个好主意。然而,还有一个后续问题:doStuff具有用户交互功能,如果用户在其间吃午饭,它很容易会占用一个小时或更长的时间。当网站在不等待回调的情况下调用该函数两次时,两个侦听器都会同时得到两个回调,最终触发4个回调。你也有这个想法吗?我也很喜欢你的想法,谢谢。为什么您使用self.port.removeListener(type,callback)
而其他人使用self.port.removeListener(callback)
?两者都正确吗?@Doug:不,类型参数不是可选的,请参阅。这似乎只是ZER0提供的代码中的一个错误。