【问题标题】:How to know the javascript event source on function scope?如何知道函数范围内的 javascript 事件源?
【发布时间】:2013-05-25 01:44:58
【问题描述】:

问题

如果没有原始事件参数,是否可以知道该函数是由用户事件还是异步事件(如回调)触发的?

背景

我正在尝试在不知道谁是原始事件触发器的更深层次的函数调用中确定事件源。

为了调用弹出或重定向登录系统,我必须知道这一点。但是这个函数是从很多地方调用的,所以我无法在所有调用者中传递事件参数。

重要提示我无法将参数传递给最终函数。不允许使用b('timer')

例如:

  <a onclick="b()" >call</a>
   <script>
 
   function a(){
      b();
   }

   function b(){
      final();
   }

   function final(){
      //Is there something like this caller.event.source ?
      console.log(this.caller.event.source)
   }
   
   setTimeout(a,1000);

在该示例中,我尝试获取 source == 'timer''onclick',或任何其他信息以确定事件来源。

更新

基于 basilikun 方法,我实现了这个解决方案:

function final(){
    var callerFunction = arguments.callee.caller,
    evtArg = callerFunction.arguments[0];
    while(callerFunction.caller){
        callerFunction = callerFunction.caller;
        if (callerFunction.arguments[0]) {
            evtArg = callerFunction.arguments[0];
        }
    }
    console.log(evtArg&&evtArg.type?'event fired by user':'event async');
}

这是finddle

还有其他方法吗?

【问题讨论】:

  • 为什么不能将参数传递给b
  • 你定义a是为了什么?
  • 所以b("timer") 是不可能的,但至少可以将某些东西传递给事件调用的第一个函数(到a)吗?
  • @Asad:抱歉,我更新了我的示例,现在调用了 a()。
  • @user1737909:我无法将参数传递给 b,因为在我的真实代码中,b 是从多个地方的文档中调用的,其中许多地方我无法管理。

标签: javascript events javascript-events


【解决方案1】:

可以在最里面的函数中抛出异常,捕获它,并使用异常来确定调用堆栈。

如何获取调用堆栈的细节是特定于供应商的(FF 中的e.stack,Opera 中的e.message,IE 和 Safari 中的粗略函数体解析),但在 eriwen.com 上存在相当健壮的实现。

至少,我可以从该页面上发布的简短 sn-p 中看出这一点。请注意,这已演变为full blown project on Github,因此可能比该页面上的 50 行 sn-p 更可靠且功能更丰富。

在您的示例中,您将使用:

function b(){
    final();
}
function final(){
   var trace = printStackTrace();
   //output trace
}


//This would be attached as the click handler for the anchor
function anchorHandler(){
   b();
}
setTimeout(function timerCallback(){
    b();
}, 1000);

根据timerCallbackanchorHandler 是否在跟踪中,您知道是什么事件触发了函数调用。

【讨论】:

  • “并使用异常来确定调用堆栈”——这让我有点颤抖……
  • 上帝听起来像地狱一样粗略。
  • 非常锋利!但是我为我的问题找到了一个更简单的解决方案。谢谢!
【解决方案2】:

假设您至少可以在第一个函数a 中传递“计时器”:

Fiddle

<a onclick="a()" >call</a>

<script>

function a(){
    b();
}

function b(){
    final();
}

function final(){
    var callerFunction = arguments.callee.caller;
    var evtArg = callerFunction.arguments[0];
    while (callerFunction.caller !== null) {
        callerFunction = callerFunction.caller;
        if (callerFunction.arguments[0]) {
            evtArg = callerFunction.arguments[0];
        }
    }
    console.log(evtArg);
}

setTimeout(function(){a("timer")}, 100);

</script>

这将为您提供函数调用链中最后一个可能的第一个参数。因此,如果您使用“正常”事件,它将为您提供事件对象。如果你使用超时,它会给你传递给第一个函数的任何东西。

请注意,此解决方案还使用了arguments.callee.caller,它应该很慢并且并非所有地方都支持。并且正如 robC 已经提到的,在严格模式下是不允许的。

【讨论】:

  • 这就是我要找的。 :)
【解决方案3】:

您可以使用 arguments.callee.caller 来访问函数对象并附加一个扩展...不确定这是否适合您的情况。请注意,这在严格模式下不起作用,因为 arguments.callee.caller 已被弃用。

<a onclick="b()" >call</a>

<script>

   function a(){
      b.calledByA = true;
      b();
   }

   function b(){
      final();
   }

   function final(){
      var caller = arguments.callee.caller;
      console.log(caller.calledByA);
      caller.calledByA = null;
   }

   setTimeout(a, 1000);

</script>

【讨论】:

  • arguments.callee.caller 也是我的第一个想法,但它仍然不会给他关于 a 被调用的事件类型的信息(超时)。
  • 如果程序调用总是在b上设置expandos,可以通过演绎来完成。
猜你喜欢
  • 2017-06-08
  • 1970-01-01
  • 2018-01-08
  • 2011-02-13
  • 2017-01-20
  • 2015-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多