如何绕过隐藏标签中的setTimeout油门?

时间:2014-12-02 16:16:31

标签: javascript webgl

我正在做一个沉重的“科学”(即不显示数据)webgl计算。 Webgl不能放在一个worker中,并且做了很多webgl会阻塞整个浏览器,所以我把计算切成块,然后我在setTimeout()函数中计算每个块(在调用getError()之后刷新opengl队列)。我在块之间留下了一些时间,以便浏览器有时间从主UI队列中清除一些UI事件,这使整个事情感觉有点迟钝。

我的问题是,当隐藏选项卡时,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);

2 个答案:

答案 0 :(得分:1)

对于任何需要它的人来说,这是另一个错综复杂的解决方法;您可以使用Web Audio 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;  
})

答案 1 :(得分:-1)

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