在 interval 上调用的函数访问全局变量

Function called on interval accesses global variable

我正在异步接收数据(从每秒 0 到 100 点),这些数据将传递给高启动成本函数 extendTraces(data),该函数会更新用户界面。如果我在生成每个点时调用 extendTraces(),用户界面将变得无响应。我发现定期调用该函数并向其传递一个点数组(称为 pointArray)效率更高。

我可以跟踪有多少点被添加到 pointArray 并每添加 20 次调用 extendTraces(pointArray):

//inside asynchronous function
pointArray.push(point);
if (this.pointArray.length == 20){
    (<any>Plotly).extendTraces(this.pointArray);
    this.resetPointArray();
}

但是如果我中途填充pointArray并且一段时间没有收到任何数据,我也会调用extendTraces。

我的解决方案是每秒调用一次 extendTraces()

//inside a function that is called when the page loads
window.setInterval(function() {
    if (pointArray.length > 0){
        (<any>Plotly).extendTraces(this.pointArray);
        this.resetPointArray();
    }
}, 1000);

我接收点的函数将简单地将它们连接到 pointArray 上。

//inside asynchronous function
pointArray.push(point);

我是 js 的新手,想知道我是否使用了正确的范例来完成这项任务。我看到很多关于回调和承诺的信息,我并不完全理解,但我怀疑我没有使用它们做错了什么。来自 c++,我担心两个函数,setInterval 中定义的函数和接收点的异步函数,都可以访问 pointArray 而无需任何硬编码互斥体。

你应该创建一个 debounce 函数,这基本上限制了函数的调用频率。这是下划线库中的去抖功能:

// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
_.debounce = function(func, wait, immediate) {
  var timeout, result;

  var later = function(context, args) {
    timeout = null;
    if (args) result = func.apply(context, args);
  };

  var debounced = restArguments(function(args) {
    if (timeout) clearTimeout(timeout);
    if (immediate) {
      var callNow = !timeout;
      timeout = setTimeout(later, wait);
      if (callNow) result = func.apply(this, args);
    } else {
      timeout = _.delay(later, wait, this, args);
    }

    return result;
  });

  debounced.cancel = function() {
    clearTimeout(timeout);
    timeout = null;
  };

  return debounced;
};

现在只需将 extendTraces 函数包裹在 debounce 函数周围,然后从中调用 return 的函数。

来源:https://github.com/jashkenas/underscore/blob/master/underscore.js#L887-L914

我很想将逻辑包装到它自己的 class 中,它只允许您指定

  • 添加多少次后调用方法
  • 在多长时间不活动后调用方法
  • 调用方法

function PointHandler(flushSize, flushTime, flushCallback){
 
  var pointArray = [];
  var lastFlush = setTimeout(() => this.flush(),flushTime)
  
  this.addPoint = function(point){
      pointArray.push(point);
      if(pointArray.length == flushSize){
          this.flush();          
      }
      clearTimeout(lastFlush)
      lastFlush = setTimeout(() => this.flush(), flushTime);
  }
  
  this.flush = function(){
      flushCallback(pointArray);
      pointArray = [];
      clearTimeout(lastFlush)
      lastFlush = setTimeout(() => this.flush(), flushTime);
  }

}

var handler = new PointHandler(10, 5000, points => console.log(points));

document.getElementById("clickme").addEventListener("click", () => handler.addPoint(new Date()));
<button id="clickme">Add point</button>

以上代码将在闲置 5 秒后或添加 10 点时调用回调。

我的回调只是 console.log 当前点,但您可以调用您的方法。