2014-12-02 61 views
0

我正在做一个沉重的“科学”(即不显示数据)webgl计算。 Webgl不能放在工作人员中,并且执行大量webgl会阻止整个浏览器,因此我将块计算成块,然后在setTimeout()函数中计算每个块(在调用getError()以刷新opengl队列)。我在块之间留出了一些时间,以便浏览器有时间从主UI队列中刷新一些UI事件,并且使整个事情感觉不那么迟钝。如何绕过隐藏选项卡中的setTimeout节流阀?

我的问题是,当标签被隐藏时,setTimeout被限制到一秒的时间段,对我来说太慢了。

有没有比我做的更好的解决方案?很明显,requestAnimationFrame()不起作用,因为它永远不会在隐藏的标签中回调(并且它可见的速度太慢)。

在隐藏状态下是否存在非节流时间事件?我试图使用window.postMessage(),但它仍然太快,整个浏览器感觉很慢。

这里是我研究的当前状态:

  function drawTile(sequenceIndex) { 
       if (sequenceIndex < sequence.length) { 
        var x = sequence[sequenceIndex][0]; 
        var y = sequence[sequenceIndex][1]; 
        setTilePos(x, y); 
        modelStage.render(renderer, modelBuffer); 
        minkowskiPass.render(renderer, minkowskiBuffer, modelBuffer); 
        copyPass.quad.position.x = x; 
        copyPass.quad.position.y = y; 
        copyPass.render(renderer, null, minkowskiBuffer); 
        var gl = renderer.getContext(); 
        gl.getError(); 
        sequenceIndex++; 
        if (document.visibilityState != "hidden") { 
         setTimeout(function() { 
          drawTile(sequenceIndex); 
         }, 10); 
        } else { 
         //window.postMessage is not rate limited then the tab is hidden 
         // we need to slow the computation by an event, otherwise the whole browser is unresponsive. 
         $(window).one('message', function() { 
          drawTile(sequenceIndex); 
         }); 
         window.postMessage('lol', '*'); 
        } 
       } else 
        console.timeEnd('computation'); 
      } 
      console.time('computation'); 
      drawTile(0); 
+0

我发现了一个令人费解的“解决方案”通过将setTimeout的()中似乎并不成为速率限制,如主线程工人。我仍然对更简单的系统开放。 – nraynaud 2014-12-03 06:52:16

+0

不是。您不能强制客户端执行您的计算。你的实际用例是什么,“太慢”是什么意思? – Bergi 2014-12-03 14:08:18

+0

我发布的代码是直接从我的应用程序,你想要更多的细节?我正在用webgl进行几何转换。太慢意味着滴答速度不够快,并且会降低全局计算速度。 – nraynaud 2014-12-03 18:45:22

回答

1

对于任何需要它的人来说,这是另一个令人费解的解决方法;您可以使用Web音频API生成函数调用:

var setTimeout2 = (function() { 
    var samples = 2048; 
    var fns = []; 
    var context = new AudioContext(); 
    var source = context.createBufferSource(); 
    var node = context.createScriptProcessor(samples, 1, 1); 

    // This gets fired every ~46 milliseconds. You can change 
    // `samples` to another valid value (256, 512, 1024, 2048, 
    // 4096, 8192, or 16384); then it'll get called every 
    // `samples/context.sampleRate` seconds (~46 ms for 
    // `samples == 2048` and `context.sampleRate == 44100`). 
    node.onaudioprocess = function (e) { 
     fns = fns.filter(function (fn) { 
      return !fn(Date.now() - fn.t); 
     }); 
    }; 
    source.connect(node); 
    node.connect(context.destination); 
    window.do_not_garbage_collect = [context, source, node]; 

    return function (fn) { 
     fn.t = Date.now(); 
     fns.push(fn); 
    }; 
}()); 

// Use like this: 
setTimeout2(function (t) { 
    console.log(t); 

    // End after 1 second. 
    if (t > 1000) 
     return true; 
}) 
+0

ahah,我的一位朋友也提出了这个建议。疯狂的头脑。 – nraynaud 2015-06-02 14:20:41

-1

也许有一个工作线程同时运行了 postMessage的循环和时间(每n次迭代)的一小部分,无论是暂停或恢复主线程?

相关问题