当事件使用setTimeout / setInterval排队,并且用户正在查看单独的标签时,Chrome和Firefox会在执行事件之前强制执行至少1000毫秒的延迟。 This article详细说明了行为。
之前已在StackOverflow上讨论过,但问题和答案仅适用于动画。显然,当用户重新进入选项卡时,可以强制动画更新到最新状态。
但该解决方案不适用于有序音频。我有Web Audio API按顺序播放多个音频文件,setTimeout用于倒计时播放下一个音频文件。如果你把标签放在后台,你会在每个模式之间产生令人讨厌的1秒间隙 - 这是专为高级音频设计的API中的一个极端缺陷。
您可以在各种HTML5序列发生器中见证此行为,例如:使用PatternSketch - 只需输入图案,播放并转到另一个标签页。
所以我需要一种解决方法:一种在没有1000ms钳位的情况下排队事件的方法。有谁知道一种方式?
我能想到的唯一解决方案是让window.postMessage每隔一毫秒运行一次,并检查每次是否要执行该事件。这绝对不利于表现。这是唯一的选择吗?
显然没有为Web Audio API规划事件系统,所以这是不可能的。
答案 0 :(得分:2)
编辑:另一个答案是每个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中测试)。我会把你留给其他人。
哦,如果父母掉线,不要忘记自动关闭子窗口。