Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/azure/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 删除“;包装的;用于发布/订阅消息的事件处理程序_Javascript_Jquery_Javascript Events_Publish Subscribe - Fatal编程技术网

Javascript 删除“;包装的;用于发布/订阅消息的事件处理程序

Javascript 删除“;包装的;用于发布/订阅消息的事件处理程序,javascript,jquery,javascript-events,publish-subscribe,Javascript,Jquery,Javascript Events,Publish Subscribe,我已经使用jQuery事件完成了一些发布/订阅 基本功能工作: var publish = function(name) { // --- works var args = Array.prototype.slice.call(arguments); // convert to array args = args.slice(1); // remove arg1 (name)

我已经使用jQuery事件完成了一些发布/订阅

基本功能工作:

var publish = function(name) {                        // --- works
  var args = Array.prototype.slice.call(arguments);   // convert to array
  args = args.slice(1);                               // remove arg1 (name)
  $("html").trigger(name, args);
}

var subscribe = function(name, callback) {            // --- works
  $("html").on(name, callback);
}

var unsubscribe = function(name, callback) {          // --- works
  $("html").off(name, callback);
}

// usage:                                             // --- works
var myhandler = function () { /* ... */ };
subscribe("foo", myhandler);
publish("foo", 1, false, "bob", {a:1, b:"2"});
unsubscribe("foo", myhandler);
但以我想要的方式订阅,不会:

var subscribe = function(name, callback) {            // --- can't unsub this
  $("html").on(name, function () {
    var args = Array.prototype.slice.call(arguments);
    args = args.slice(1);
    callback.apply(null, args);
  });
}
我需要第二个
subscribe
函数,因为匿名回调会删除第一个参数(一个
事件
对象),而我不希望它出现在“干净”的客户端代码中。我只想在回调中接收事件数据,而不需要事件对象本身

但这意味着我无法成功调用
unsubscribe
,因为我没有传入
off()
与传入
on()
相同的回调-这不是实际的回调,而是一个包装的匿名函数


有办法解决这个问题吗?

通常的方法是使用jQuery的:

然后取消订阅:

$("html").off(name + ".my-pub-sub");
这告诉jQuery删除具有给定事件名称和特定命名空间的所有处理程序

下面是一个简化的示例:

//添加两个单击处理程序:
$(“按钮”)。在(“单击”,函数(){
$(“无名称空间单击“

”).appendTo(document.body); }); $(“按钮”)。在(“click.namespace”,function()上{ $(“名称空间单击“

”).appendTo(document.body); }); //显示它们都触发了 $(“单击…

”).appendTo(document.body); $(“按钮”)。单击(); //删除不带函数ref的命名空间文件 $(“按钮”).off(“单击名称空间”); //现在只运行无名称空间的一个 $(“再次单击…

”).appendTo(document.body); $(“按钮”)。单击()


按钮
可以返回新创建的事件处理程序,如下所示:

var subscribe = function(name, callback) {
  var handler = function () {
    var args = Array.prototype.slice.call(arguments);
    args = args.slice(1);
    callback.apply(null, args);
  };
  $("html").on(name, handler);
  return handler;
};
var myhandler = function () { console.log(arguments); };
var eventHandler = subscribe("foo", myhandler);
publish("foo", 1, false, "bob", {a:1, b:"2"}); // logs to console
unsubscribe("foo", eventHandler);
publish("foo", 1, false, "bob", {a:1, b:"2"}); // don't log anymore
现在您可以这样使用它:

var subscribe = function(name, callback) {
  var handler = function () {
    var args = Array.prototype.slice.call(arguments);
    args = args.slice(1);
    callback.apply(null, args);
  };
  $("html").on(name, handler);
  return handler;
};
var myhandler = function () { console.log(arguments); };
var eventHandler = subscribe("foo", myhandler);
publish("foo", 1, false, "bob", {a:1, b:"2"}); // logs to console
unsubscribe("foo", eventHandler);
publish("foo", 1, false, "bob", {a:1, b:"2"}); // don't log anymore

以下是

我所做的是基于@tjcrower提出的名称空间思想。但我已经把他的回答记为“谢谢”

var subscribe = function(name, callback) {

  // create a unique "key" for this specific event handler
  // - use this format: ORIGINALNAME.MILLISECONDS.RANDOMNUMBER
  // - include time in random string, as could be lots of subs happening at once
  // - then include a random number, just to be safe
  var key = name + "." + (new Date().getTime()) + (Math.random()*1000);

  $("html").on(key, function () {
    var args = Array.prototype.slice.call(arguments);
    args = args.slice(1);
    callback.apply(null, args);
  });

  return key;
}

var unsubscribe = function (key) {
  $("html").off(key);
};

// usage:
var myhandler = function () { /* ... */ };
var key = subscribe("foo", myhandler);
publish("foo", 1, false, "bob", {a:1, b:"2"});
unsubscribe(key);

因为这个键是唯一的(好吧,应该是?!),所以它只会删除这个特定的处理程序。所以我可以有很多订阅者,而其中只有一个是不明嫌犯。

是的,但是如果我有多个订阅者参加那个活动呢。如果我使用
off()
和一个名称空间,它将删除所有的名称空间,而不仅仅是我想要的名称空间?@hbob:您可以为每个订阅者分配一个不同的名称空间。总之,在取消订阅时,您需要一些标识您要删除的内容的内容(或者是您要附加的实际函数,或者是特定的命名空间)。@TJCrowder:Yes有意义。我添加了我的解决方案作为答案,您认为如何?不过,我接受你的建议,因为你给了我最初的想法。这似乎很好。(除了:
Math.random()*(1000-0)+0
?这与
Math.random()*1000
)完全相同)当然,如果你想记住一些独特的东西,你可以返回对你正在创建的函数的引用。您希望在取消订阅时释放引用,这很容易做到:
key=unsubscribe(key)
由于
取消订阅
不返回任何内容,调用它会导致
未定义
,它被分配到
,因此函数不再对它有任何引用,并且可以进行垃圾收集。@TJCrowder虽然您是100%正确的,而且您的方法更简单,我想我更喜欢返回唯一的字符串作为键。使忘记强制垃圾收集器的开发人员在使用该函数时不易发生内存泄漏。对。只存在函数的一个副本,返回的值将是对该函数的引用。“使忘记强制垃圾收集器的开发人员使用该函数时不太容易发生内存泄漏”是和否。如果他们不清除
,则会出现此字符串。但是字符串可能比函数小。没有太多(对于您展示的函数),但仍然…思考一下:不仅仅是函数,函数关闭的上下文,以及这些上下文引用的任何内容,所以尽管字符串可能不会比函数小很多,但我打赌它比函数在RAM中保留的所有内容都小得多。打得好。原来这和@TJCrowder的建议是一样的。很好用!