Chrome에서 탭이 비활성 상태일 때 setInterval도 작동하도록 하려면 어떻게 해야 합니까?
는 나나 a a a가 있다setInterval
1초에 30번씩 코드를 실행해요이것은 훌륭하게 동작합니다만, 다른 탭을 선택하면(코드가 있는 탭이 비활성화됩니다),setInterval
는 어떤 이유로 아이돌 상태로 설정되어 있습니다.
이 간단한 테스트 케이스를 만들었습니다(http://jsfiddle.net/7f6DX/3/):
var $div = $('div');
var a = 0;
setInterval(function() {
a++;
$div.css("left", a)
}, 1000 / 30);
이 코드를 실행한 후 다른 탭으로 전환하고 몇 초간 기다렸다가 다시 돌아가면 애니메이션은 다른 탭으로 전환한 시점에서 계속됩니다.
따라서 탭이 비활성화된 경우 애니메이션이 초당 30회 실행되지 않습니다.이것은, 이 테스트의 회수를 세는 것으로 확인할 수 있습니다.setInterval
함수는 매초 호출됩니다.탭이 비활성화되면 30이 아니라 1 또는 2가 됩니다.
시스템 퍼포먼스를 향상시키기 위한 설계라고 생각합니다만, 이 동작을 무효로 하는 방법이 있습니까?
사실 제 시나리오에서는 단점입니다.
대부분의 브라우저의 비활성 탭은 우선순위가 낮으며 이는 JavaScript 타이머에 영향을 줄 수 있습니다.
각 간격마다 고정된 증분 대신 프레임 간에 실시간 경과된 시간을 사용하여 전환 값을 계산한 경우, 이 문제를 회피할 수 있을 뿐만 아니라 프로세서가 그다지 비지 상태가 아니라면 최대 60fps까지 얻을 수 있으므로 부탁한다 Animation Frame을 사용하여 더 많은 애니메이션을 얻을 수 있습니다.
'JavaScript'를 사용한 입니다.requestAnimationFrame
:
var target = document.querySelector('div#target')
var startedAt, duration = 3000
var domain = [-100, window.innerWidth]
var range = domain[1] - domain[0]
function start() {
startedAt = Date.now()
updateTarget(0)
requestAnimationFrame(update)
}
function update() {
let elapsedTime = Date.now() - startedAt
// playback is a value between 0 and 1
// being 0 the start of the animation and 1 its end
let playback = elapsedTime / duration
updateTarget(playback)
if (playback > 0 && playback < 1) {
// Queue the next frame
requestAnimationFrame(update)
} else {
// Wait for a while and restart the animation
setTimeout(start, duration/10)
}
}
function updateTarget(playback) {
// Uncomment the line below to reverse the animation
// playback = 1 - playback
// Update the target properties based on the playback position
let position = domain[0] + (playback * range)
target.style.left = position + 'px'
target.style.top = position + 'px'
target.style.transform = 'scale(' + playback * 3 + ')'
}
start()
body {
overflow: hidden;
}
div {
position: absolute;
white-space: nowrap;
}
<div id="target">...HERE WE GO</div>
백그라운드 태스크용(UI 관련 없음)
@UpTheCreek 코멘트:
프레젠테이션 문제에는 문제가 없지만 계속 실행해야 할 몇 가지 사항이 있습니다.
지정된 간격으로 정확하게 실행해야 하는 백그라운드 태스크가 있는 경우 HTML5 웹 작업자를 사용할 수 있습니다.자세한 내용은 아래 Möhre의 답변을 참조하십시오.
CSS와 JS의 '애니메이션'
이 문제와 기타 많은 문제는 JavaScript 기반의 애니메이션 대신 CSS 트랜지션/애니메이션 사용으로 피할 수 있습니다.이것에 의해, 오버헤드가 큰 것이 됩니다.이 jQuery 플러그인을 추천합니다.이 플러그인은 CSS 이행의 이점을 얻을 수 있습니다.animate()
★★★★★★★★★★★★★★★★★★.
오디오 페이딩과 HTML5 플레이어에서도 같은 문제가 발생했습니다.탭이 비활성화되었을 때 막혔어요.그래서 WebWorker는 제한 없이 인터벌/타임아웃을 사용할 수 있다는 것을 알게 되었습니다.메인 Javascript에 ticks를 올리기 위해 사용합니다.
웹 워커 코드:
var fading = false;
var interval;
self.addEventListener('message', function(e){
switch (e.data) {
case 'start':
if (!fading){
fading = true;
interval = setInterval(function(){
self.postMessage('tick');
}, 50);
}
break;
case 'stop':
clearInterval(interval);
fading = false;
break;
};
}, false);
주요 Javascript:
var player = new Audio();
player.fader = new Worker('js/fader.js');
player.faderPosition = 0.0;
player.faderTargetVolume = 1.0;
player.faderCallback = function(){};
player.fadeTo = function(volume, func){
console.log('fadeTo called');
if (func) this.faderCallback = func;
this.faderTargetVolume = volume;
this.fader.postMessage('start');
}
player.fader.addEventListener('message', function(e){
console.log('fader tick');
if (player.faderTargetVolume > player.volume){
player.faderPosition -= 0.02;
} else {
player.faderPosition += 0.02;
}
var newVolume = Math.pow(player.faderPosition - 1, 2);
if (newVolume > 0.999){
player.volume = newVolume = 1.0;
player.fader.postMessage('stop');
player.faderCallback();
} else if (newVolume < 0.001) {
player.volume = newVolume = 0.0;
player.fader.postMessage('stop');
player.faderCallback();
} else {
player.volume = newVolume;
}
});
웹 워커는 별도의 프로세스로 실행되며 속도가 느려지지 않기 때문에 앞에서 설명한 바와 같이 사용하는 솔루션이 있습니다.
코드를 변경하지 않고 사용할 수 있는 작은 스크립트를 작성했습니다.set Timeout, clear Timeout, set Interval, clear 함수보다 우선합니다.간격.
모든 코드 앞에 포함시켜 주세요.
여기 있는 다른 사람들처럼 오디오를 백그라운드에서 재생하는 것은 중요하지 않습니다.문제는 애니메이션을 몇 개 가지고 있는데 다른 탭으로 돌아왔을 때 그들이 미친 듯이 행동했다는 것입니다.내 솔루션은 비활성 탭을 방지하기 위해 다음 애니메이션을 내부에 넣는 것이었습니다.
if (!document.hidden){ //your animation code here }
탭이 활성화되어 있을 때만 애니메이션이 실행되었기 때문입니다.이게 제 사건에 도움이 됐으면 좋겠어요.
다음 작업을 수행합니다.
var $div = $('div');
var a = 0;
setInterval(function() {
a++;
$div.stop(true,true).css("left", a);
}, 1000 / 30);
''을 버퍼링합니다.setInterval
★★★★★★★★★★★★★★★★★」setTimeout
★★★★★★★★★★★★★★★★★★.
stop(true,true)
버퍼링된 모든 이벤트를 중지하고 마지막 애니메이션만 즉시 실행합니다.
window.setTimeout()
메서드는 비활성 탭에서 초당 1회 이하의 타임아웃을 전송하도록 클램핑합니다.또한 HTML5 사양에서 허용되는 최소값인 4ms까지 중첩된 타임아웃을 클램프합니다(클램프에 사용하던 10ms가 아닌).
다.setInterval
★★★★★★★★★★★★★★★★★」requestAnimationFrame
탭이 비활성 상태이거나 작동하지만 올바른 기간이 아닐 때는 작동하지 않습니다.해결책은 시간 이벤트에 다른 소스를 사용하는 것입니다.예를 들어 웹 소켓이나 웹 워커는 탭이 비활성화되어 있을 때 정상적으로 작동하는 두 가지 이벤트 소스입니다.따라서 모든 코드를 웹 워커로 이동할 필요 없이 워커를 시간 이벤트 소스로 사용합니다.
// worker.js
setInterval(function() {
postMessage('');
}, 1000 / 50);
.
var worker = new Worker('worker.js');
var t1 = 0;
worker.onmessage = function() {
var t2 = new Date().getTime();
console.log('fps =', 1000 / (t2 - t1) | 0);
t1 = t2;
}
이 문제에 대해 가장 잘 이해할 수 있는 것은 http://jsfiddle.net/TAHDb/의 예라고 생각합니다.
여기서는 간단한 일을 하고 있습니다.
1초의 간격을 두고 매번 첫 번째 스팬을 숨기고 마지막 스팬으로 이동한 후 두 번째 스팬을 표시합니다.
페이지를 유지하면 원래대로 작동합니다.단, 탭을 몇 초간 숨기면 돌아가면 weired가 표시됩니다.
비액티브한 시간 동안 발생하지 않았던 모든 이벤트가 한 번에 모두 처리되는 것과 같습니다.몇 초 동안 X 이벤트처럼 느껴질 거예요.6개의 스팬을 한 번에 모두 볼 수 있을 정도로 빠릅니다.
그래서 크롬은 이벤트를 지연시킬 뿐이기 때문에 당신이 돌아오면 모든 이벤트가 발생하지만 한꺼번에...
간단한 슬라이드 쇼를 위한 이 ocur iss를 사용하는 것이 기본 응용 프로그램입니다.숫자가 Images라고 상상해 보세요.사용자가 돌아왔을 때 탭을 숨긴 채로 있으면 모든 imgs가 떠 있는 것을 볼 수 있습니다.Totally mese.
이 문제를 해결하려면 pimvdb에 표시된 대로 stop(true, true)을 사용합니다.이벤트 큐가 클리어 됩니다.
루슬란 투쇼프의 도서관의 영향을 많이 받아서 나는 나만의 작은 도서관을 만들었다.스크립트 추가만 하면 됩니다.<head>
패치가 .setInterval
★★★★★★★★★★★★★★★★★」setTimeout
사용하는 것과 함께WebWorker
.
오디오 파일을 재생하면 당분간은 Javascript의 풀 백그라운드 성능을 확보할 수 있습니다.
나에게 있어서, 그것은 가장 심플하고 침입이 적은 솔루션이었다.약간 또는 거의 비어 있는 소리를 재생하는 것 이외에는, 다른 잠재적인 부작용은 없다.
상세한 것에 대하여는, https://stackoverflow.com/a/51191818/914546 를 참조해 주세요.
(다른 답변에서는 Audio 태그의 속성이 다른 사람도 있는 것을 알 수 있습니다.Audio 태그를 사용하여 실제로 재생하지 않고 성능을 최대한 높일 수 있는지 의문입니다.)
타이머 함수로 이 문제를 회피하려는 사용자를 위해 간단한 해결책을 제시하겠습니다.다른 답변에서 언급한 것처럼 @kbtzr은 시작 이후 경과된 시간을 계산하기 위해 고정 증분 대신 Date 개체를 사용할 수 있습니다.이 방법은 응용 프로그램의 탭에서 벗어나도 작동합니다.
이것은 HTML의 예시입니다.
<body>
<p id="time"></p>
</body>
다음 JavaScript:
let display = document.querySelector('#time')
let interval
let time
function startTimer() {
let initialTime = new Date().getTime()
interval = setInterval(() => {
let now = new Date().getTime()
time = (now - initialTime) + 10
display.innerText = `${Math.floor((time / (60 * 1000)) % 60)}:${Math.floor((time / 1000) % 60)}:${Math.floor((time / 10) % 100)}`
}, 10)
}
startTimer()
이렇게 하면 비활성 탭의 성능상 인터벌 값이 증가하더라도 정확한 시간이 계산됩니다.이것은 바닐라 코드입니다만, 저는 이 논리를 React 어플리케이션에서 사용하고 있기 때문에, 필요한 장소에서도 변경할 수 있습니다.
꽤 오래된 질문이지만 나는 같은 문제에 직면했다.
Chrome에서 웹을 실행하는 경우 Chrome 57에서 이 게시물 배경 탭을 읽을 수 있습니다.
기본적으로 타이머 버젯을 다 써버리지 않으면 인터벌타이머를 실행할 수 있습니다
예산 소비량은 태스크 내부 타이머의 CPU 시간 사용량에 따라 결정됩니다.
시나리오를 바탕으로 캔버스에 비디오를 그리고 WebRTC로 전송합니다.
webrtc 비디오 연결은 탭이 비활성화되어 있어도 계속 업데이트됩니다.
단, 사용하셔야 합니다.setInterval
대신requestAnimationFrame
단, UI 렌더링에는 권장되지 않습니다.
듣는 게 좋을 거야visibilityChange
사건과 변화는 그에 따라 메천니즘을 낳는다.
또한 Kaan Soral이 제안하는 것을 시험해 볼 수 있으며, 이는 문서에 근거해 작동해야 합니다.
기능하는 UI를 추가하여 Lacerda의 응답을 수정했습니다.
시작/재개/일시정지/정지 액션을 추가했습니다.
const
timer = document.querySelector('.timer'),
timerDisplay = timer.querySelector('.timer-display'),
toggleAction = timer.querySelector('[data-action="toggle"]'),
stopAction = timer.querySelector('[data-action="stop"]'),
tickRate = 10;
let intervalId, initialTime, pauseTime = 0;
const now = () => new Date().getTime();
const formatTime = (hours, minutes, seconds) =>
[hours, minutes, seconds]
.map(v => `${isNaN(v) ? 0 : v}`.padStart(2, '0'))
.join(':');
const update = () => {
let
time = (now() - initialTime) + 10,
hours = Math.floor((time / (60000)) % 60),
minutes = Math.floor((time / 1000) % 60),
seconds = Math.floor((time / 10) % 100);
timerDisplay.textContent = formatTime(hours, minutes, seconds);
};
const
startTimer = () => {
initialTime = now();
intervalId = setInterval(update, tickRate);
},
resumeTimer = () => {
initialTime = now() - (pauseTime - initialTime);
intervalId = setInterval(update, tickRate);
},
pauseTimer = () => {
clearInterval(intervalId);
intervalId = null;
pauseTime = now();
},
stopTimer = () => {
clearInterval(intervalId);
intervalId = null;
initialTime = undefined;
pauseTime = 0;
},
restartTimer = () => {
stopTimer();
startTimer();
};
const setButtonState = (button, state, text) => {
button.dataset.state = state;
button.textContent = text;
};
const
handleToggle = (e) => {
switch (e.target.dataset.state) {
case 'pause':
setButtonState(e.target, 'resume', 'Resume');
pauseTimer();
break;
case 'resume':
setButtonState(e.target, 'pause', 'Pause');
resumeTimer();
break;
default:
setButtonState(e.target, 'pause', 'Pause');
restartTimer();
}
},
handleStop = (e) => {
stopTimer();
update();
setButtonState(toggleAction, 'initial', 'Start');
};
toggleAction.addEventListener('click', handleToggle);
stopAction.addEventListener('click', handleStop);
update();
html, body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
body {
display: flex;
justify-content: center;
align-items: center;
background: #000;
}
.timer {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 0.5em;
}
.timer .timer-display {
font-family: monospace;
font-size: 3em;
background: #111;
color: #8F8;
border: thin solid #222;
padding: 0.25em;
}
.timer .timer-actions {
display: flex;
justify-content: center;
gap: 0.5em;
}
.timer .timer-actions button[data-action] {
font-family: monospace;
width: 6em;
border: thin solid #444;
background: #222;
color: #EEE;
padding: 0.5em;
cursor: pointer;
text-transform: uppercase;
}
.timer .timer-actions button[data-action]:hover {
background: #444;
border: thin solid #666;
color: #FFF;
}
<div class="timer">
<div class="timer-display"></div>
<div class="timer-actions">
<button data-action="toggle" data-state="initial">Start</button>
<button data-action="stop">Stop</button>
</div>
</div>
주의: 이 솔루션은 오디오 재생 등 백그라운드에서 인터벌을 실행하는 경우에는 적합하지 않습니다.그러나 페이지나 탭으로 돌아갈 때 애니메이션이 제대로 작동하지 않는 등 혼란스러운 경우에는 이 방법이 좋습니다.
이 목표를 달성하기 위한 방법은 여러 가지가 있습니다.아마 'WebWorkers'가 가장 표준적일 수도 있지만, 가장 쉽고 편리한 방법은 아닙니다.특히 시간이 부족할 경우에는 다음과 같이 시도해 볼 수 있습니다.
기본 개념:
사용자가 처음 페이지를 열 때 실행되도록 간격(또는 애니메이션)의 이름을 만들고 간격(메모)을 설정합니다.
var interval_id = setInterval(your_func, 3000);
타고
$(window).focus(function() {});
그리고.$(window).blur(function() {});
넌 할 수 있다.clearInterval(interval_id)
브라우저(탭)가 동작할 때마다 재실행하고 브라우저(탭)가 다시 동작할 때마다 인터벌(애니메이션)을 재실행합니다.interval_id = setInterval();
샘플 코드:
var interval_id = setInterval(your_func, 3000);
$(window).focus(function() {
interval_id = setInterval(your_func, 3000);
});
$(window).blur(function() {
clearInterval(interval_id);
interval_id = 0;
});
여기 대략적인 해결책이 있습니다.
(function(){
var index = 1;
var intervals = {},
timeouts = {};
function postMessageHandler(e) {
window.postMessage('', "*");
var now = new Date().getTime();
sysFunc._each.call(timeouts, function(ind, obj) {
var targetTime = obj[1];
if (now >= targetTime) {
obj[0]();
delete timeouts[ind];
}
});
sysFunc._each.call(intervals, function(ind, obj) {
var startTime = obj[1];
var func = obj[0];
var ms = obj[2];
if (now >= startTime + ms) {
func();
obj[1] = new Date().getTime();
}
});
}
window.addEventListener("message", postMessageHandler, true);
window.postMessage('', "*");
function _setTimeout(func, ms) {
timeouts[index] = [func, new Date().getTime() + ms];
return index++;
}
function _setInterval(func, ms) {
intervals[index] = [func, new Date().getTime(), ms];
return index++;
}
function _clearInterval(ind) {
if (intervals[ind]) {
delete intervals[ind]
}
}
function _clearTimeout(ind) {
if (timeouts[ind]) {
delete timeouts[ind]
}
}
var intervalIndex = _setInterval(function() {
console.log('every 100ms');
}, 100);
_setTimeout(function() {
console.log('run after 200ms');
}, 200);
_setTimeout(function() {
console.log('closing the one that\'s 100ms');
_clearInterval(intervalIndex)
}, 2000);
window._setTimeout = _setTimeout;
window._setInterval = _setInterval;
window._clearTimeout = _clearTimeout;
window._clearInterval = _clearInterval;
})();
오디오 태그와 on timeupdate 이벤트를 사용하여 최소 250ms의 콜백 기능을 호출할 수 있었습니다.1초에 3~4번 정도 불러요.1초의 지연 set Timeout보다 낫다.
이 문제에 대한 회피책이 있지만, 실제로는 일부 창에서 탭을 활성화해야 합니다.
- 비활성 탭을 별도의 브라우저 창으로 만듭니다.
- 다른 창을 최대화하지 마십시오(최대화된 창이 뒤에 있지 않은 경우).
이것에 의해, 브라우저는 항상 액티브한 인상을 받을 수 있습니다.
이것은 조금 번거롭지만 빠른 승리이기도 하다.창문의 배치를 제어할 수 있는 경우.
언급URL : https://stackoverflow.com/questions/5927284/how-can-i-make-setinterval-also-work-when-a-tab-is-inactive-in-chrome
'programing' 카테고리의 다른 글
리액트 후크 useState()와 오브젝트 (0) | 2022.11.07 |
---|---|
mariadb 이미지에 대해 루트 사용자가 아닌 도커 컨테이너를 실행할 수 없습니다. (0) | 2022.11.07 |
브라우저 뷰포트에 상대적인 요소의 맨 위 위치를 가져오려면 어떻게 해야 합니까? (0) | 2022.11.07 |
php.ini: 어떤 거요? (0) | 2022.11.07 |
PHMailer로 이메일 보내기 - 이미지를 본문에 포함 (0) | 2022.11.07 |