在 Javascript 中以一定速度循环遍历数组

Loop through array at certain speed in Javascript

我是新来的所以请放过我。

我正在做我的一个小爱好项目,其中一个应用程序收集遥测数据,该遥测数据以 60Hz 的频率记录和保存(因此数组中每秒有 60 个索引)。总是这样。

然后我想 'play through' 这个阵列以正常速度播放,就像您正在播放视频一样。但是我不想看视频,而是想在前端显示您所在的每个索引的当前数据。

数组的结构还没有建立,但我想我会在数据库的某个地方存储和加载一个 JSON 文件。然后应该在我的前端播放。我已经使用 Angular (6) 来构建它,所以如果它可以与 Angular 混合使用会很棒(以跟踪您现在所在索引的进度,并绑定值当前索引的前端)。

indexx 只使用 0-1-2-etc 或类似时间戳之类的东西会容易吗?

欢迎提出任何建议。这里最重要的是保持快速,这样你就不需要强大的装备来玩这个。

提前致谢!

您需要使用 setInterval 函数,在该函数中您将根据频率遍历数组。因此,如果您的频率是 60hz,这意味着您希望每 1000 / 60 毫秒

后迭代到数组中的下一个元素
var data = [1, 2, 3, 4, 5]

var currentIndex = 0;

var interval = 1000 / 60

var id = setInterval(function() {
  // do your thing
  if(currentIndex == (data.length-1)) {
    clearInterval(id)
  } else {
    currentIndex++
  }
}, interval)

这不是对数组的特别迭代,而是在一段时间间隔后执行一些操作,然后移动到下一个项目,当您完成数组时,这将清除间隔。也许链表在这里比数组更有帮助

你可以让自己成为这些事情的简单跑步者。它基本上是一个游戏引擎,你需要一个游戏循环:)

这是一个天真的例子。为了 brewity,这里跳过大部分错误检查和验证。

class TelemetryPlayer {
  constructor(items, render, interval) {
    // setup local data. 
    this.interval = interval;
    this.items = items;
    this.render = render;
    this.startLoop();
  }

  // Loop simply initializes before the first run, and then runs the loop.
  // Other places do the actual work. 
  startLoop() {
    this._renderInProgress = false;
    this._currentIndex = 0;
    // save the interval reference if you wanna pause/reset later on.
    this._interval = setInterval(this.doWork.bind(this), this.interval);    
  }

  // here we perform the actual render.
  doWork() {
    if (this._renderInProgress) {
      // previous render has not completed yet.
      console.log('skip');
      return;
    }
    console.log('Tick');
    this._renderInProgress = true;
    const item = this.items[this._currentIndex];
    console.log('Tick');

    // now, call your renderer, and update stuff when complete.
    this.render(item)
      .then(() => {
        // Or this can be a callback or similar.
        this._renderInProgress = false;
        // Ready next item. Do not go out of array bounds.
        this._currentIndex++;
        if (this._currentIndex === this.items.length) {
          this._currentIndex = 0;
        }
      });
  }

  // You can then add fun things like skip, pause, reset etc.
  skip(item)  {
    if (item < 0 || item > this.items.length) {
      return;
    }
    // pause first
    this.pause();
    this._currentIndex = item;
    this.unpause();
  }
  //
  reset() {
    this.skip(0);
  } 
  //
  pause() {
    this._interval = clearInterval(this._interval);
  }

  unpause() {
    if (!this._interval) {
      this._interval = setInterval(this.doWork.bind(this), this.interval);    
    }
  }

  // you can even add items later
  addItem(item) {
    this.items.push(item);
  }

  // or replace them.
  replaceItem(item, index) {
    this.items[index] = item;
    // show the new item right away.
    this.skip(index);
  }

  // or add an item to be played just once.
  playOnce(item) {
    this.pause();
    this.render(item);
    this.unpause();
  }
}

下面是一个用法示例。您可以复制代码(上面的 class 和下面的代码块)并将其粘贴到 Whosebug 上的控制台中,以查看它的工作情况。你可能想做其他事情,但你会明白要点的。

let items = [ 100, 200, 300, 50, 100, 200, 300, 250 ];

const timeline = document.createElement('ul');
// maybe better do this by adding class and external stylesheet
timeline.setAttribute('style', 'padding: 15px; border: 1px solid gray; list-style-type: none; height: 500px; width: 100%; position: absolute; top: 0;overflow-y: scroll;')
document.body.appendChild(timeline);

let render = function(item)  {
  return new Promise(function (resolve) {
    // run something (in) expensive with item now.
    const li = document.createElement('li');
    // again, better do this with class.
    li.setAttribute('style', `display: inline-block; width: 25px; margin: 5px; background-color: #c1c1c1; height: ${item}px;`);
    timeline.appendChild(li);
    li.scrollIntoView();

    // return when done.
    resolve();
  });
}

const player = new TelemetryPlayer(items, render, 1500);

// now you can do things like speed up etc.


// now you can do things like speed up etc.
function speedUp() {
  // speedup 3 seconds after "playback" starts.
  return new Promise((resolve) => setTimeout(() => {
    player.pause();
    player.interval = 600;
    player.unpause();
    resolve();
  }, 3000));  
}    

function playOnce() {
  // add item once, but not in the array we loop around in
  return new Promise((resolve) => setTimeout(() => {
    player.playOnce(1000);
    resolve();
  }, 3000));  
}
// or add a few items that will be repeated.
function addItems() {
  // add a super very high item 3 seconds after function call.
  return new Promise((resolve) => setTimeout(() => {
    player.pause();
    player.addItem(400);
    player.addItem(430);
    player.addItem(420);
    player.unpause();
    // now rewind to this block. I am off by one, likely.
    player.skipTo(player.items.length - 3);
    resolve();
  }, 5000))
}

speedUp()
.then(playOnce)
.then(addItems);