2

Question

Is it possible to know if the function was fired by a user event or an async event (like callback) without having the original event parameter?

Background

I'm trying to determine the event source in a deeper function call which doesn't know who was the original event trigger.

I have to know that in order to call a popup or redirection login system. But this function is called from many places, so I can't pass the event parameter in all callers.

Important: I'm not able to pass parameters to the final function. b('timer') is not allowed.

e.g:

  <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);

In that example, I'm trying to get source == 'timer' or 'onclick', or any other information to determine which is the event origin.

Update

Based on basilikun approach I've implemented this solution:

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');
}

This is the finddle

Any other approach?

4

3 回答 3

3

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

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

至少,这是我从该页面上发布的简短片段中可以看出的。请注意,这已经发展成为Github 上的一个完整项目,因此可能比该页面上的 50 行代码段更可靠且功能丰富。

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

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跟踪中,您知道是什么事件触发了函数调用。

于 2013-05-24T14:58:30.640 回答
2

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

小提琴

<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 已经提到的,在严格模式下是不允许的。

于 2013-05-24T15:41:00.740 回答
1

您可以使用 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>
于 2013-05-24T15:25:19.927 回答