在javascript

时间:2017-01-31 12:04:05

标签: javascript executioncontext

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

例如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,它们都会在有机会递减计数器之前递增计数器

1 个答案:

答案 0 :(得分: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这样对C真正私密:

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

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