当事件使用setTimeout/setInterval排队时,并且用户正在查看单独的选项卡时,Chrome和Firefox在执行事件之前强制执行至少1000ms的延迟。 This article详细说明了行为。

前面已经在StackOverflow上对此进行了讨论,但是问题和答案仅适用于动画。显然,当用户重新进入选项卡时,动画只能被强制更新为最新状态。

但是该解决方案不适用于定序音频。我有Web Audio API依次播放多个音频文件,并且setTimeout用于倒数播放下一个音频文件的时间。如果将选项卡放在背景中,则每个模式之间会出现1秒钟的烦人间隙-这是专为高级音频设计的API中的一个极端缺陷。

您可以在各种HTML5定序器中看到这种行为,例如使用PatternSketch-只需输入一个模式,播放,然后转到另一个选项卡即可。

因此,我需要一种变通方法:一种在没有1000ms钳位的情况下将事件排队的方法。有人知道吗?

  • 我唯一想到的解决方案是让window.postMessage每毫秒运行一次,并每次检查事件是否要执行。这绝对不利于性能。这是唯一的选择吗?
  • 显然,没有为Web Audio API计划任何事件系统,因此这是毫无疑问的。
  • 最佳答案

    编辑:另一个答案是每个https://stackoverflow.com/a/12522580/1481489使用WebWorker -这个答案有点具体,所以这里有一些更通用的东西:

    interval.js

    var intervalId = null;
    onmessage = function(event) {
        if ( event.data.start ) {
            intervalId = setInterval(function(){
                postMessage('interval.start');
            },event.data.ms||0);
        }
        if ( event.data.stop && intervalId !== null ) {
            clearInterval(intervalId);
        }
    };
    

    和你的主程序:
    var stuff = { // your custom class or object or whatever...
        first: Date.now(),
        last: Date.now(),
        callback: function callback() {
            var cur = Date.now();
            document.title = ((cur-this.last)/1000).toString()+' | '+((cur-this.first)/1000).toString();
            this.last = cur;
        }
    };
    
    var doWork = new Worker('interval.js');
    doWork.onmessage = function(event) {
        if ( event.data === 'interval.start' ) {
            stuff.callback(); // queue your custom methods in here or whatever
        }
    };
    doWork.postMessage({start:true,ms:250}); // tell the worker to start up with 250ms intervals
    // doWork.postMessage({stop:true}); // or tell it just to stop.
    

    丑陋的,但是您可以打开一个子弹出窗口。但是,所有这些操作只是将一些警告转移到了子窗口上,即如果最小化了子窗口,则会出现1000ms的问题,但是如果它根本不在焦点上,就没有问题了。然后,如果它关闭了,它就会停止,但是用户要做的就是再次单击“开始”按钮。

    因此,我想这并不能真正解决您的问题...但这是一个草稿:
    var mainIntervalMs = 250;
    
    var stuff = { // your custom class or object or whatever...
        first: Date.now(),
        last: Date.now(),
        callback: function callback(){
            var cur = Date.now();
            document.title = ((cur-this.last)/1000).toString()+' | '+((cur-this.first)/1000).toString();
            this.last = cur;
        }
    };
    
    function openerCallbackHandler() {
        stuff.callback(); // queue your custom methods in here or whatever
    }
    
    function openerTick(childIntervalMs) { // this isn't actually used in this window, but makes it easier to embed the code in the child window
        setInterval(function() {
            window.opener.openerCallbackHandler();
        },childIntervalMs);
    }
    
    // build the popup that will handle the interval
    function buildIntervalWindow() {
        var controlWindow = window.open('about:blank','controlWindow','width=10,height=10');
        var script = controlWindow.document.createElement('script');
        script.type = 'text/javascript';
        script.textContent = '('+openerTick+')('+mainIntervalMs+');';
        controlWindow.document.body.appendChild(script);
    }
    
    // write the start button to circumvent popup blockers
    document.write('<input type="button" onclick="buildIntervalWindow();return false;" value="Start" />');
    

    我建议您找到一种更好的组织,编写等方式,但是至少它应该为您指明正确的方向。它也应该可以在许多差异浏览器中使用(理论上,仅在chrome中测试)。我让你休息。

    哦,如果父窗口掉落,别忘了建立子窗口的自动关闭功能。

    关于javascript - setTimeout/setInterval在后台标签(Chrome和Firefox)中滞后1000ms,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19475894/

    10-12 13:20