prevent javascript from pausing after switching browser tabs [duplicate] - javascript

This question already has answers here:
How can I make setInterval also work when a tab is inactive in Chrome?
(16 answers)
Closed 5 days ago.
I have a problem. I have a script that decreases the width of an element for 15 seconds. The script works normally, however when switching to another browser tab, the script pauses its execution, and only resumes when I return to the script tab again.
I looked all over the internet and I couldn't find anything that could solve this problem.
I want the user to be able to visit other tabs and for the script to continue decreasing the width of the file, based on the seconds that have been configured.
does anyone know if it's possible?
I looked all over the internet for a solution and I couldn't find it.
my code
var contagemInicial = document.querySelector('.seconds'),
life = document.querySelector('.life'),
time = contagemInicial.textContent,
[segundos, centesimos] = time.split(":")
var contagem = setInterval(() =>{
//life.classList.add('animar')
if (centesimos == 00) {
centesimos = 60
segundos--
life.style.width = (segundos / 15 * 100) + '%'
life.style.transition = 'linear 1.2s'
} else {
centesimos--
if (centesimos < 10) {
centesimos = '0'+centesimos
}
}
if (segundos == 0 && centesimos == 00) {
clearInterval(contagem)
}
contagemInicial.textContent = segundos+':'+centesimos
}, 14)

It's because optimization. Inactive pages have lower priority. You can work around this by calculating elapsed time between each update (recommended way) or use web workers since they not affected by this "issue". You can read more about this here, there are some great answers.

Related

Firefox is throttling setInterval [duplicate]

This question already has answers here:
Controlling fps with requestAnimationFrame?
(15 answers)
Closed 3 years ago.
I'm trying to make a web-based game and I use setInterval to update the game (positions, collision checks, etc...) 60 times a second.
It works fine in most browsers, but for some reason Firefox sometimes throttles it to about 35 times a second. Yes, sometimes. If DevTools is closed, it will throttle, but if you open DevTools and start recording performance, it jumps to 60 and will stay that way until DevTools is closed.
If you're using Firefox, run the snippet and try it:
var cycles = 0;
setInterval(()=>{
cycles++;
}, 1000/60);
setInterval(()=>{
console.log("Update cycles per second: %i", cycles);
cycles = 0;
}, 1000);
Is this a bug? If not, why does this happen and how can I work around it?
Edit: I'm not using setInterval to render. For that I use requestAnimationFrame. I'm using setInterval to update the game at a constant time interval, because requestAnimationFrame fires before repainting, and is heavily dependent on the refresh rate of the user's screen.
You should not rely on timers being accurate. They often aren't. Instead, rely on time being accurate:
var cycles = 0, start = Date.now();
setInterval(() => {
cycles = Math.floor((Date.now() - start) / 1000 * 60);
}, 1000/60);
That said, requestAnimationFrame is probably a better choice for your use than setInterval, as it gets called on every rerender.

Javascript: Click 'Next' only if a Qualtrics page has not been viewed

Background
I have implemented (code below) a countdown timer in Qualtrics using the Javascript and CSS found in this post: http://codejaxy.com/q/55868/javascript-timer-qualtrics-qualtrics-progress-to-next-block-when-time-is-up# The exact code I have produced (which simply implements the solution proposed in that post) is found in the 'Current Code' section below.
The code for the countdown timer automatically clicks Next and advances to a new screen when time is up. Which screen it advances to is based on the display logic of each question following that on the current screen (see items 3 and 4 in 'Current Code').
Problem
While this can successfully move someone to the end of a timed section of a survey (i.e. once time is up, you are moved out of the timed section to another, subsequent set of questions that are untimed), it also causes the screen to advance even if one is finished with the timed section. In other words, if the intent is to move a person from any question in the timed question set X to the first question in the untimed question set Y after Z time has passed, if one answers all of the questions in X before Z time has passed, one will be moved from a question in Y to a subsequent question in Y. Essentially, one might end up skipping a question you want a person to answer rather than skipping the remainder of the timed section.
Question
Is there any way to have the code click "Next" only if a certain question has not been viewed? Or maybe reaching a certain point of the survey causes the blockTimeFlag to = 0 and not be changed when time runs out?
In other words, my goal is to not cause the participant to be unable to answer a question in an untimed block of questions because the screen advances automatically upon the timer indicating time is up while the participant has already completed that part.
Current Code
(1) Added the following custom CSS in the survey Look and Feel:
.header-cont {
width:100%;
position:fixed;
top:0px;
z-index:1000;
}
.header {
height:75px;
background:#FFFFFF;
width:100%;
margin:0px auto;
}
.timer{
margin: auto;
text-align: center;
vertical-align: middle;
font-size: 200%;
font-family: Arial;
}
(2) Created a 'Timing' question and included the following in the Javascript (note: this incorporates the solution offered in that post):
Qualtrics.SurveyEngine.addOnload(function()
{
var headerCont = document.createElement("div");
headerCont.className = "header-cont";
headerCont.id = "header_container";
var header = document.createElement("div");
header.className = "header"
header.id = "header_1";
var timer = document.createElement("div");
timer.className = "timer";
timer.id = "timer_1";
timer.innerHTML = "Time Remaining: <span id='time'>00:10</span>";
headerCont.appendChild(header);
header.appendChild(timer);
document.body.insertBefore(headerCont, document.body.firstChild);
function startTimer(duration, display) {
var timer = duration, minutes, seconds;
var myTimer = setInterval(function() {
minutes = parseInt(timer / 60, 10)
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
var text = ('innerText' in display)? 'innerText' : 'textContent';
display[text] = minutes + ":" + seconds;
if (--timer < 0) {
clearInterval(myTimer);
timeOver();
}
}, 1000);
}
var timerSeconds = 5,
display = document.querySelector('#time');
startTimer(timerSeconds, display);
var timeOver = function() {
document.getElementById("timer_1").innerHTML = "Time is up.";
Qualtrics.SurveyEngine.setEmbeddedData("blockTimeFlag", "1");
$('NextButton').click();}
});
(3) Created an embedded data field in the survey flow before the timer containing blockTimeFlag = 0.
(4) Set the display logic for items based on blockTimeFlag = 0 (i.e. if the blockTimeFlag = 1 - which occurs when time is up - then the item is skipped0
I'm assuming your JavaScript is in the survey header or footer. If that is the case, you can put your code in an if statement that checks the value of an embedded variable. This would allow you to turn the timer on or off on a block by block basis by setting the value of the embedded variable.
Qualtrics.SurveyEngine.addOnload(function()
{
if("${e://Field/timerOnOff}" == "on"} {
var headerCont = document.createElement("div");
/* the rest of your code here... */
}
});
This feels like it has two solutions. One is rethinking the architecture of your code to make this an easier issue to solve, but I'm gonna post the quick and dirty solution that comes to my mind at the moment.
From what I understand, the user is advanced once the timer is up, even when they are already past the timed section, and you cannot interfere with the timer itself once it is set. Therefore, the easiest solution i can think of is:
Once the user hits the first question of section Y as you called it, alter the function timeOver(). Make it do whatever, just be careful not to set it to null, since it will still be called and would then throw an error.
If you want a more...structured solution, I would suggest making your timer globally available (or rather as far out as it has to be, global state isn't a good thing from what I know). Then, you can call clearInterval() as soon as the user proceeds to the first question of section Y.

Chrome slows down javascript if page is not active [duplicate]

This question already has answers here:
How can I make setInterval also work when a tab is inactive in Chrome?
(16 answers)
Closed 5 years ago.
If I write a javascript code what uses setTimeout/setInterval, time will not be valid on Chrome if the related page isn't active.
To demonstrate, just simply create an html file with a js code like this:
<script>
var title = 1;
setInterval(function(){document.title = "X:"+title; title+=1}, 250);
</script>
Open page several time, and you'll see that if a page is not active, the title will increment only in abount 2 sec, instead of 250ms. It is a very critical issue in my development.
Does anyone know how to evade it? A simple Chrome options could be enought too if there is.
Just to mark it as not duplicate: It is not for animations, it is for background workings. The provided example is very accurate! I need to run script in very accurately and do operations fastly in backgrounded tabs. I know, 99,9999% of people does not need it...
Neither function is considered accurate by intention. You never should rely on provided timespans. This inaccuracy can be stressed to some amount by browser when your page isn't visible.
Actually it doesn't make sense to keep working in background using a regular webpage. If you really need to do that try some WebWorker instead. The webpage is for user interaction ... user interaction does not happen in background by intention. Processing things in background is best put in a worker thread. So, it's all about runtime context matching code's conceptual intention.
Adding to what cepharum has, it is impossible to guarantee that your code will be execute every 250ms exactly. Chrome is not a real time operating system, and neither is your code. Depending on the implementation of the interpreter, it may even experience drifts and delays.
With that being said, if you only want to reduce the delay, you can use a worker to trick the system by creating a new thread that will not have its refresh rate limited:
function createWorker(main){
var blob = new Blob(
["(" + main.toString() + ")(self)"],
{type: "text/javascript"}
);
return new Worker(window.URL.createObjectURL(blob));
}
// Worker
var worker = createWorker(function(self){
setInterval(function(){
self.postMessage(Date.now());
}, 250);
});
worker.onmessage = function(e) {
console.log("Worker: " + e.data);
}
https://jsfiddle.net/DerekL/ouzcdh9g/
I ran into the same issue before, the way I solved it was to use math to calculate the time difference, instead of rely on the setInterval being reliable. E.g.
var title = 1;
var tickTime = (new Date()).getTime();
setInterval(function(){
var now = (new Date()).getTime();
document.title = "X:"+title;
// you can adjust the math calculation below to
// meet your requirements
title+= (now - tickTime)/250;
tickTime = now;
}, 250);

JavaScript setInterval delay when screen sleeps [duplicate]

This question already has an answer here:
Are there any standards for mobile device web browsers in terms of thread sleeping? [closed]
(1 answer)
Closed 8 years ago.
I'm developing a chronometer app in Tizen and I'm currently using the setInterval function to schedule the next time the text with the numbers will be updated:
chrono : function() {
SecondsChrono += 1;
},
setInterval(chrono(), 1000);
But when the device's screen is put on "sleep mode" the chronometer gets delayed.
I want to know if anyone has experienced this and if you have some way to avoid it or if you have any advice for me to implement this chronometer in another way.
You should use setInterval only to update the screen, to see how much time has ellapsed since the chronometer first started you should do something like this:
var SCREEN_UPDATE_REFRESH_RATE= 1000;
var startTime= (new Date()).getTime();
var updateScreen= function() {
var currentTime= (new Date()).getTime();
var timeEllapsed = currentTime - startTime; //this value is in milliseconds
document.write("Ellapesed time in seconds: " timeEllapsed / 1000);
setTimeout(updateScreen, SCREEN_UPDATE_REFRESH_RATE);
}
updateScreen();
It is better to use setTimeout in this case than setInterval. The difference between the two is that setInterval schedules the function to execute forever every X milliseconds while setTimeout schedules to execute once and then never again, in this case the function sets a new timeout that keeps the updating process forever. If your user system is overloaded various setInterval callbacks can be chained together which can freeze the user browser. See this for more information.

Precise timing on setTimeout function [duplicate]

This question already has answers here:
Is there a more accurate way to create a Javascript timer than setTimeout?
(16 answers)
Closed 9 years ago.
I need to reproduce an animation-like effect on the browser (mobile and desktop), this effect is just a procedural changes on the background color from black to white.
The timming is important, since a black background for a short time means "0" and a longer time means "1" (is like a binary Morse code). This information is interpreted by a light sensor in front of the screen. The sensor is very fast, and if we use a lower frequency we wont have problems with the screen (assuming a maximum refresh rate of 50Hz).
This is the script im using:
var i = 0;
var b0t = 100;
var b1t = 3.5 * b0t;
var wl = 100;
function pulses (){
bytes = "1001101010110101001000100";
bit = bytes[i];
i += 1;
document.body.style.backgroundColor = 'white';
document.body.style.color = 'white';
setTimeout(toblack, wl);
if(i <= bytes.length) {
if (bit == 1)
setTimeout(pulses, b1t + wl);
else
setTimeout(pulses, b0t + wl);
}
}
function toblack() {
document.body.style.backgroundColor = 'black';
document.body.style.color = 'black';
}
pulses ();
And a working demo (Do not open if you suffer any epileptic syndrome)
The problem is, 1 out of 20 the browser mess the timing, of course in the sensor side i have a tolerance range, a very tolerant range, but again the browser some times is out by several milliseconds, and this is no surprise, if your computer of cellphone is doing something in the background the performance of the browser is severely affected.
Is there a software solution for this? I was thinking using flash to do the flickering with more precision, but i really like my app to be accessible also from IOS. Or i can make a native app that for sure will be more precise than the browser, but then again, i will like to know if i can make it work on the browser.
the only thing i can suggest you to try is, forget about sestTimeout and try Date().getTime() it will give you a microsecond unix timestamp and you can try to query that and implement your own set timeout... i dont know if that will work, but you lost nothing trying.
take a look here http://www.sitepoint.com/creating-accurate-timers-in-javascript/
there are some examples.

Categories

Resources