Optimal solution to creating a “run loop” in JavaScript

Deadly 提交于 2019-12-04 18:47:22
Paul

You can yield to the event loop inside a while loop with async/await:

// This can only be logged when the event loop
// is yielded to in the infinite loop below.
// So, it can only ever be logged between `#1` and `#2` being logged;
// it can sometimes occur more than once, or not at all between `#1` and `#2`
const interval = setInterval( _ => console.log( '#1.5' ), 0 );

(async _ => {

  // Using a for loop so this demo doesn't run forever.
  // Can use an infinite loop instead
  for ( let i = 0; i < 150; i++ ) { // while( true ) {

    console.log( '#1 About to yield, ' );
    await new Promise( resolve => setTimeout( _ => resolve(), 0 ) ); // yield
    console.log( '#2 Done yielding (other callbacks may have run)' );

  }

  clearInterval( interval );

})();

In node.js use setImmediate instead of setTimeout. Do not use process.nextTick.

To demo with your timer:

var start = (new Date()).getTime()
var q = 0, x = 1000;

;(async _ => {
  while (q < x) {
    await new Promise( resolve => setTimeout( _ => resolve(), 0 ) );
    q++
  }

  var end = (new Date).getTime()
  console.log('a', end - start)
})();

Something like this will work:

var THRESHOLDCOUNT = 10000
var THRESHOLDTIME = 15

function loop(fn) {
  var start = Date.now()
  var changed = false
  var x = 0

  while (!changed) {
    while (x < THRESHOLDCOUNT) {
      x++
      fn()
    }

    var end = Date.now()
    changed = end - start > THRESHOLDTIME
  }

  // make room for external events.
  setImmediate(loop)
}

If you really need a performant loop, I'd say go with requestAnimationFrame(), it's highly optimized and pretty easy to use.

https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!