问题描述
当事件使用setTimeout / setInterval排队,并且用户正在查看单独的选项卡时,Chrome和Firefox会在事件执行前至少延迟1000毫秒。 详细介绍了这种行为。 p>先前已经在StackOverflow上讨论过这个问题,但问题和答案只适用于动画。显然,当用户重新进入标签页时,动画只能被迫更新到最新状态。
但是这个解决方案对于有序音频无效。我有Web Audio API按顺序播放几个音频文件,setTimeout用于在下一个音频文件播放时进行倒计时。如果你把这个标签放在后台,你会在每个模式之间产生一个令人讨厌的1秒的差距 - 这个API是为高级音频设计的一个极端的缺陷。
这种行为在各种HTML5顺序器中,例如与 - 此答案是一个小的具体,所以这里是更通用的: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);
}
};
和您的主程序:
<$ p $ (),
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(); //将你的自定义方法排列在这里或者任何
}
};
doWork.postMessage({start:true,ms:250}); //告诉工作者以250ms的间隔启动
// doWork.postMessage({stop:true}); //或告诉它只是停止。
完全丑陋,但是你可以打开一个儿童弹出窗口。但是,所有这些都是向子窗口传递一些警告,即如果子窗口最小化,则出现1000毫秒的问题,但是如果它简单地失焦,则不存在问题。然后,如果它关闭,那么它会停止,但所有的用户所要做的就是再次点击开始按钮。
所以,我想这不是真的解决你的问题...但这里是一个粗略的草案:
pre $ var mainIntervalMs = 250;
$ b $ var stuff = {//您的自定义类或对象或任何...
第一: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;
}
};
函数openerCallbackHandler(){
stuff.callback(); //将你的自定义方法放在这里或者任何
}
函数中openerTick(childIntervalMs){//这个实际上并没有在这个窗口中使用,但是更容易嵌入代码子窗口
setInterval(function(){
window.opener.openerCallbackHandler();
},childIntervalMs);
//建立处理时间间隔的弹出窗口
函数buildIntervalWindow(){
var controlWindow = window.open('about:blank',' controlWindow, '宽度= 10,高度= 10');
var script = controlWindow.document.createElement('script');
script.type ='text / javascript';
script.textContent ='('+ openerTick +')('+ mainIntervalMs +');';
controlWindow.document.body.appendChild(script);
}
//写入开始按钮以绕过弹出窗口阻止程序
document.write('< input type =buttononclick =buildIntervalWindow(); return false; value =Start/>');
我建议找出一个更好的方法来组织,写等,但至少应该指出你在正确的方向。它也应该在很多差异浏览器中工作(理论上,只在Chrome中进行测试)。我会把你留给其余的。
哦,不要忘了在父窗口自动关闭的情况下自动关闭子窗口。
When events are queued with setTimeout/setInterval, and the user is viewing a separate tab, Chrome and Firefox enforce a minimum 1000ms lag before the event is executed. This article details the behaviour.
This has been discussed on StackOverflow previously, but the questions and answers only applied to animations. Obviously, an animation can just be forced to update to the latest state when a user re-enters the tab.
But the solution does not work for sequenced audio. I have Web Audio API playing several audio files in sequence, and setTimeout is used to countdown to when the next audio file plays. If you put the tab in the background, you get an annoying 1 second gap between each pattern -- an extreme flaw in an API designed for advanced audio.
You can witness this behaviour in various HTML5 sequencers, e.g. with PatternSketch -- just by entering a pattern, playing, and going to another tab.
So I'm in need of a workaround: a way to queue events without the 1000ms clamp. Does anyone know of a way?
The only solution I can think of is to have window.postMessage run every single millisecond and check each time if the event is to execute. That is definitely detrimental to performance. Is this the only option?
Apparently there is no event system planned for Web Audio API, so that is out of question.
EDIT: Another answer is to use WebWorker
s per https://stackoverflow.com/a/12522580/1481489 - this answer is a little specific, so here's something more generic:
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);
}
};
and your main program:
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.
Totally ugly, but you could open up a child popup window. However, all this does is transfer some of the caveats to the child window, i.e. if child window is minimized the 1000ms problem appears, but if it is simply out of focus, there isn't an issue. Then again, if it is closed, then it stops, but all the user has to do is click the start button again.
So, I suppose this doesn't really solve your problem... but here's a rough draft:
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" />');
I'd recommend working out a better way to organize, write, etc. but at the least it should point you in the right direction. It should also work in a lot of diff browsers (in theory, only tested in chrome). I'll leave you to the rest.
Oh, and don't forget to build in auto-closing of the child window if the parent drops.
这篇关于setTimeout / setInterval在后台标签(Chrome和Firefox)中延迟1000毫秒的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!