如何最大化异步调度程序的性能?

时间:2016-08-08 16:47:13

标签: javascript performance asynchronous optimization micro-optimization

我注意到JavaScript中的一种奇怪的技术,我已经习惯于在画布上绘制的重复过程中提高性能。将来,我计划在实施时使用SharedBufffer甚至SharedCanvas,但与此同时,这是我使用的一般概念:

function someContinuousProcess(intervals, delay) {
  var count = 0;
  var span = document.querySelector('span');

  function someExpensiveFunction() {
    if (count >= 1e9) {
      return false;
    }

    do {
      count++;
    } while (count % 1e5);

    span.textContent = count;
    
    return true;
  }
  
  function wrapper(index) {
    var start = performance.now();
    
    if (someExpensiveFunction()) {
      var delta = performance.now() - start;
      // some logic here to determine new 
      // values for `intervals` and `delay`
      scheduler[index] = setTimeout(
        wrapper.bind(null, index),
        delay
      );
    }
  }

  var scheduler = [];

  function startScheduler() {
    for (var i = 0; i < intervals; i++) {
      scheduler[i] = setTimeout(
        wrapper.bind(null, i),
        delay
      );
    }
  }

  function stopScheduler() {
    for (var i = 0; i < scheduler.length; i++) {
      clearTimeout(scheduler[i]);
    }

    scheduler = [];
  }

  startScheduler();
}

int.onchange = del.onchange = () => {
  var intervals = parseInt(int.value);
  var delay     = parseInt(del.value);

  if (!isNaN(intervals) && !isNaN(delay)) {
    someContinuousProcess(intervals, delay);
  }
};
<input placeholder=intervals id=int>
<input placeholder=delay id=del>
<span></span>

如果你搞砸了参数,你会发现当然delayintervals都会对性能产生重大影响。但有一点,如果你设置了太多intervals一段延迟,性能提升将变成性能下降,同时使线程无响应。

我的问题是,是否可以根据给定的intervals自适应地选择delaysomeExpensiveFunction?假设我们可以someExpensiveFunction()返回高分辨率时间戳performance.now(),那么我们如何使用它来智能地改变intervalsdelay以优化性能?

1 个答案:

答案 0 :(得分:0)

这似乎是使用网络工作者的绝佳机会。它们在一个单独的线程中执行,因此它们不会影响主线程上的动画。

但是,仍然要求您不要经常postMessage,或者主线程中的事件循环会对大量消息产生阻塞。

&#13;
&#13;
function simple() {
  var span = $('#v1');
  var worker = new Worker('data:text/javascript;charset=UTF-8,' + encodeURI($('#someExpensiveFunction').text()));

  worker.onmessage = progress => span.text(progress.data);
  worker.onerror = x => {
debugger;
  };
}

function withanim() {
  var span = $('#v2');
  var worker = new Worker('data:text/javascript;charset=UTF-8,' + encodeURI($('#someExpensiveFunction').text()));

  var latestMessage = 0;
  worker.onmessage = progress => latestMessage = progress.data;
  worker.onerror = x => {
debugger;
  };

  var myReq;
  function step(timestamp) {
span.text(latestMessage);
if (latestMessage < 1e9)
  myReq = requestAnimationFrame(step);
  }
  myReq = requestAnimationFrame(step);
}

simple();
withanim();
&#13;
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js" 
type="text/javascript" charset="utf-8"></script>
<div id=v1></div>
<div id=v2></div>
<script type="text/worker" id="someExpensiveFunction">
var count = 0;
var start = performance.now();
var reportPerSec = 100; //change this
var delay = 1000/reportPerSec;
do {
  //some un-interrupable task
  //it might be useful to put this in a setTimeout(0), if you also want to use onmessage to get data to work on from the main thread
do {
count++;
  } while (count % 1e2);
  
  //report progress
  if (performance.now() - start > delay) {
 	postMessage(count);
start = performance.now();
  }
} while (count < 1e9);
postMessage(count); //make sure to send 'done'
</script>
&#13;
&#13;
&#13;

Fiddle