1

我正在使用严格模式。我想比较是否在同一个执行上下文堆栈中对同一个函数进行了两次调用。

例如 1:如果两个独立的事件处理程序 A 和 B 被触发并且它们每个都调用 C,那么我想知道对 C 的调用是在不同的执行上下文堆栈中进行的。

A->C
B->C

例如 2:如果函数 A 调用了 C 而调用了 B 又调用了 C,那么我想确定对 C 的两次调用是在同一个执行上下文堆栈中进行的。

A->C->B->C

我需要这种行为,因为我在 Javascript 中实现应用程序事务,并且我希望能够支持嵌套事务。当我们编写严格的代码时,我正在寻找不使用参数、被调用者、调用者对象的解决方案。

还要记住,A、B、C 都可以是异步的,并且 C 在调用时不会立即运行完成。这就是为什么使用下面描述的计数器在异步场景中不起作用的原因

C() {
   return Promise.resolve().then(() => {
        let result = someFunction();
        return result;
   })
}

B() {
    doSomethingSync();

    if(someCondition) {
        C();
    }
}

C是异步的。使用计数器,这意味着两个独立的事件处理程序调用 C,它们都在有机会减少计数器之前增加计数器

4

1 回答 1

2

我将假设您在单线程上下文中运行它(例如浏览器1或 NodeJS)。

如果是这样,这两种情况之间的区别在于 C 是通过间接递归调用的,因此一个简单的状态变量可以告诉您是否发生了这种情况。

最简单的形式当然是计数器:

var callstoC = 0;
function C() {
    ++callsToC;
    // ...code here that checks `callsToC`: If it's `1`, it's not recursive;
    // if it's `> 1`, it's recursive (indirectly or directly)
    --callsToC;
}

您可以使它比跟踪状态更复杂(例如使用数组来记住每个调用的参数是什么,以防万一——例如,用于报告目的)。

显然,所有离开函数的路由正确记录你离开函数是关键。

现场示例:

function hook(selector, event, handler) {
  var elements = document.querySelectorAll(selector);
  for (var n = 0; n < elements.length; ++n) {
    elements[n].addEventListener(
      event,
      handler,
      false
    );
  }
}
hook("#btnA, #btnB, #btnD", "click", function() {
  console.log(this.id + " calling C");
  C(this.id == "btnD");
});

var callsToC = 0;
function C(flag) {
  ++callsToC;
  console.log("C called with flag = " + flag + ", callsToC = " + callsToC);
  if (flag) {
    D();
  }
  console.log("C about to decrement and exit, callsToC = " + callsToC);
  --callsToC;
}
function D() {
  console.log("D calling C");
  C(false);
  console.log("D done");
}
.as-console-wrapper {
  max-height: 80% !important;
}
<input type="button" id="btnA" value="A">
<input type="button" id="btnB" value="B">
<input type="button" id="btnD" value="D">


callsToC在评论中,您有一个全球性的担忧。它不一定是,我不会让它成为全球性的,甚至不会像C; 我只是不想使示例复杂化。我会像这样使它真正私有给C:

var C = (function() {
    var callsToC = 0;
    return function C() {
        // ...
    };
})();

1虽然浏览器支持多线程(通过网络工作者),但它们不支持在多线程中使用相同的功能;每个线程都有自己的全局上下文。

于 2017-01-31T12:07:58.247 回答