So to start and avoid confusion, the code below is what sparked my thought, it doesn't necessarily have much to do much with my question except for an example to explain where my question is coming from.
I was just looking at some code in javascript here:
https://jsfiddle.net/Daniel_Hug/pvk6p/
var h1 = document.getElementsByTagName('h1')[0],
start = document.getElementById('start'),
stop = document.getElementById('stop'),
clear = document.getElementById('clear'),
seconds = 0, minutes = 0, hours = 0,
t;
function add() {
seconds++;
if (seconds >= 60) {
seconds = 0;
minutes++;
if (minutes >= 60) {
minutes = 0;
hours++;
}
}
h1.textContent = (hours ? (hours > 9 ? hours : "0" + hours) : "00") + ":" + (minutes ? (minutes > 9 ? minutes : "0" + minutes) : "00") + ":" + (seconds > 9 ? seconds : "0" + seconds);
timer();
}
function timer() {
t = setTimeout(add, .1);
}
timer();
/* Start button */
start.onclick = timer;
/* Stop button */
stop.onclick = function() {
clearTimeout(t);
}
/* Clear button */
clear.onclick = function() {
h1.textContent = "00:00:00";
seconds = 0; minutes = 0; hours = 0;
}
The person seemed to use recursion to make a stop watch, in timer and add.
If I do it recursively, by changing this function to this:
function timer() {
add();
}
it takes up stack space, and eventually breaks, stops some where under 3:00:00.
But then I realized in the original code they used setInterval(), which just creates a separate thread then ends the thread, releasing the stack space. The code just does this repeatedly which is why the stack doesn't seem to overflow.
What I am having a hard time understanding is how does this work on a lower level? In one of my courses I took, I was required to make my own memory allocator(which i understand takes up heap space), but we never had to worry about threads and am wondering how I will do it with this.
So lets say I have a thread, and then the kernel switches to another thread, and then another, then one thread ends and another one begins, I am assuming there is going to be gaps in the stack in between threads ending and being created, correct?. I read in another post (more related to java, not sure if programming language matters) that each thread takes its own space on the stack. So I was wondering, each time I make a thread, does it just fill in gaps like a memory allocator does? What if a thread ends up taking up too much space? Does the program know to realloc memory somewhere else? Am I thinking of this wrong?
Javascript is single threaded. See, for example, https://stackoverflow.com/questions/13504811. The main and the single javascript thread has one queue of ready tasks, and one queue of timed tasks. It cycles over the first queue until it is empty, then over the second queue until all timed tasks with exceeded time limit are executed, and the sleeps until new ready task appear, or time comes of some timed tasks.
Expression setTimeout(add, .1) just adds a task to the queue of timed tasks. It will be executed when the .1 timeout exceeded, and the main thread is able to execute next tasks.
Related
in order to run a same script multiple times, i currently use ;
For example, i will run something like this
node RocketLaunch.js;node RocketLaunch.js;node RocketLaunch.js
This works great and run my script 3 times back to back. I am wondering is there an easy way i can run these 3 with gap of 1 hour?
Edit - Thank you for the responses, i am new to learning programming so apologize for posting this in JS, since it seems like a non JS question.
More information - The way i want to intend to use it, run this script every 1 hour for lets say 20 hours/times. The entire job takes around 5 minutes after i run the script and i want it to run every hour and do that 5 minutes job.
So perhaps run a command at Bash level, where i can type it 20 times with a delay of an hour. It runs every hour for 20 hours, then i can do the whole thing again.
This is how I typically do this in bash:
for x in {1..3};
do
node RocketLaunch.js
sleep 3600
done
The {1..3} tells the for loop to do this 3 times, and the sleep function takes the number of seconds as its argument. (3600 = 60 seconds * 60 minutes)
Here is the updated answer to your question
Now just run node RocketLaunch.js 1 20 This is the command to tell the script to run every 1 hour for the next 20 hours.
const rockets = {
launched: () => {
//your job
console.log("I'm A Rocket");
}
};
var arg = process.argv;
const times = Number(arg.slice(2)[1]);
const hours = Number(arg.slice(2)[0]) * 3600000; // to make the hour;
function launch() {
var x = 1
//kick off rockets at script start
rockets.launched();
timer = setInterval(() => {
rockets.launched();
x++
if (x === times) {
clearInterval(timer);
}
}, hours) //1000 ms = 1 second
}
launch();
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.
I can't use alot of the NPM libraries out there for an accurate timer as it relies on Node which I'm not using.. but the formula is pretty simple. Here's a JSfiddle of what I'm using:
http://jsfiddle.net/zryNf/9/
setPercentageBar(page) {
if (this.state.pagesById[page.id].active) {
let pagesByIdCopy = Object.assign({}, this.state.pagesById);
let pageCopy = pagesByIdCopy[page.id];
let percent = (100.0 / parseFloat(page.durationTime)) / 10;
pageCopy.percentage += percent;
this.setState({pagesById: pagesByIdCopy});
pageCopy.progressBarNextAt += this.progressBarTime; // this.progressBarTime = 100
console.log('start time');
console.log(pageCopy.progressBarStart);
console.log('next at');
console.log(pageCopy.progressBarNextAt);
console.log('drift');
console.log((new Date().getTime() - pageCopy.progressBarStart) % 100);
console.log('Date().getTime():');
let currTime = new Date().getTime();
console.log(currTime);
console.log('interval time');
console.log(pageCopy.progressBarNextAt - currTime);
console.log('--------------------------------------------------------\n');
if (pageCopy.percentage < 100) {
pageCopy.progressBarTimer = setTimeout(() => this.setPercentageBar(pageCopy),
pageCopy.progressBarNextAt - currTime);
}
}
}
It's not the exact code as I'm doing this in React, but it's the exact same formula.
I except use a 100ms delay as I am using this to update a progress bar and I need the progress bar to roll out smoothly.
I'm logging the startTime, nextAt time, drift, and interval time and it always started out well. But at some point.. the interval times become negative and i don't know why! And then everything starts messing up from that point forward. I've tried multiple formulas of this accurate timer and it happens everytime eventually. Once the interval time becomes negative.. they all become negative.
Anyone have an idea why and what can i do to fix it?
here are some example logs
https://pastebin.com/Cpfpf1Gp
EDIT: i have at most 5 timers going at 100ms each
There is no guarantee that the setTimeout callback function will be executed at exactly the desired time. If at that time other JavaScript code is running, that will first have to run to completion before the next event in the event queue gets processed, and a timer event is such an event.
So it might well be that you get the following scenario:
At 0ms: currTime is 0, progressBarNextAt is 100, and you call setTimeout(progressBarNextAt, 100). All is perfect.
At 1ms: The next event in the event queue is some callback for the real processing that is happening
At 220ms: that callback finishes, the next event in the event queue is the timer (which is late), and your function setPercentageBar gets called a second time
At 221ms: progressBarNextAt is increased from 100 to 200, which is not enough as we are already passed that moment. You print an interval time of -21.
There can even be some asynchronous code scheduled before the timer event gets processed, in the form of micro tasks. For instance, if the processing in the second bullet point has some promises that resolve immediately, the corresponding then callback functions will still execute as part of that task, and only when all of those have executed, will the timer event get its turn.
Note also that non-JS factors can influence how long a certain task takes. If the machine gets in a heavy load, and the operating system reallocates resources, this may impact an otherwise light JavaScript task. Browsers also tend to delay the processing of timer events when the window in question is not on the foreground. And there can be still other reasons.
The code in the question seems to have taken something very simple and made it a bit complicated. Instead of trying to patch up that complexity with a "drift" calculation, why don't we take a simpler approach?
The key point is to decouple these two things:
When to update the progress bar.
How to calculate the current percentage or fraction of completion.
Instead, let's just have an update() function that can be called at any time and will always do the right thing. Its calculation will not depend at all on how often or when we call it.
Also, when you use setTimeout() or setInterval() for animation, you're likely to get some fairly jumpy results. We can use requestAnimationFrame() instead for a smoother animation. (It's still not perfect, but it's better than you'll get with a timer.)
So it might look like something like this:
function progressBar( duration ) {
setValue( 0 );
var startTime = +new Date;
update();
function update() {
var elapsed = +new Date - startTime;
if( elapsed > duration ) elapsed = duration;
if( elapsed < duration ) requestAnimationFrame( update );
setValue( elapsed / duration );
}
function setValue( fraction ) {
var percent = Math.floor( fraction * 100 );
document.getElementById('percent').innerHTML =
percent + '%';
document.getElementById('filler').style.width =
fraction * 100 + '%';
}
}
progressBar( 5000 );
#border {
border-color: black;
border-width: 1px;
width: 100%;
height: 20px;
}
#filler {
background-color: green;
width: 0;
height: 100%;
}
<div id="border">
<div id="filler">
</div>
</div>
<div id="percent"><div>
I have a long running task in JavaScript, which I break up in chunks with a series of nested setTimeout(processChunk, 0), similar to what is described here. However, for each invocation, setTimeout adds an additional delay of 4 ms or more. This behaviour is well known and varies across browsers.
When I attempt to keep the processing time of each chunk at 50 ms or less, these additional delays increase total processing time by at least 10%.
My question is: Can I avoid the additional delay (and thus improve the processing speed) while maintaining backwards compatibility with ES3 browsers and old IE browsers?
There is a straightforward workaround for this issue. Since the minimum delay of setTimeout is measured from when the timer is set, make sure to set timers at least 10–15 ms before each chunk should be processed. When several setTimeout are set, they queue up and the next one is invoked immediately after the previous, without the additional delay. This can be done with only 2 active timers:
function runLongTask() {
var complete = false;
function processChunk() {
if(!complete) {
/* ... process chunk, set complete flag after last chunk ... */
//set new timer
setTimeout(processChunk);
} else {
/* ... code to run on completion ... */
}
}
//set a timer to start processing
setTimeout(processChunk);
//set an extra timer to make sure
//there are always 2 active timers,
//this removes the extra delay provided
//that processing each chunk takes longer
//than the forced delay
setTimeout(processChunk);
}
Below is a working demo comparing the workaround approach to the traditional approach of setting a new setTimeout after each chunk is processed. In the workaround there is always an extra setTimeout set ahead, reducing the processing time with about 4 ms or more for each chunk (about 40 ms or more for 10 chunks, as demonstrated below), provided that each chunk takes at least 4 ms to process. Note that the workaround demonstrates the use of only 2 active timers.
function runForAtLeast15ms() {
var d = (+new Date) + 15;
while(+new Date < d);
}
function testTimeout(repetitions, next, workaround) {
var startTime = +new Date;
function runner() {
if(repetitions > 0) {
//process chunk
runForAtLeast15ms();
//set new timer
setTimeout(runner);
} else if(repetitions === 0) {
//report result to console
console.log((workaround? 'Workaround' : 'Traditional') +
' approach: ' +
((+new Date) - startTime) + ' ms');
//invoke next() function if provided
next && next();
}
repetitions--;
}
setTimeout(runner);
if(workaround){
//make sure that there are always 2
//timers running by setting an extra timer
//at start
setTimeout(runner);
}
}
//First: repeat runForAtLeast15ms 10 times
//with repeated setTimeout
testTimeout(10, function(){
//Then: repeat runForAtLeast15ms 10 times
//using a repeated set of 2 setTimeout
testTimeout(10, false, true);
});
I am trying to display several count down timers on same page. now as far as i know there are 2 ways of doing it without using jquery plugins or some other scripts (if you know of a good one please let me know)
starting 1 sec setInterval and a global variable that will contain milliseconds and then just reduce -1000 every interval.
creating a function that reduce 1 sec from a global variable and then at the bottom of that function setting a setTimeout of 1 sec that will run that functions so basically recursion every 1 sec.
My question is which of the 2 options will work better and/or faster?
here is demonstrative code for both:
setInterval:
var amount_of_seconds_left = 46800000;
setInterval(function(){
if(amount_of_seconds_left > 1000){
amount_of_seconds_left -= 1000;
}
},1000);
setTimeout:
var amount_of_seconds_left = 46800000;
function startTime(){
if(amount_of_seconds_left > 1000){
amount_of_seconds_left -= 1000;
t=setTimeout(function(){startTime()},1000);
}
}
Both ways could work but i was wondering performance wise which is better and is performance is even an issue with this ?
setInterval and setTimeout don't start after 1000ms e.g. if another script is running, so both can cause delays. It would be better to use the setIntervall to call the display update only and use the the Date object to calculate the exactly remaining time. E.g. after the browser was busy the timer shows the correct time after the next update.
Here an example:
HTML:
<div id="timer1"></div>
<div id="timer2"></div>
javascript:
// update all timer
function updateTimer() {
for (var i in aTimer) {
var oTimer = document.getElementById(aTimer[i].sId);
var iSeconds = parseInt((aTimer[i].iFinished - Date.now()) / 1000);
oTimer.innerHTML = iSeconds;
}
}
// Init all timers with DOM-id and finish time
var aTimer = [
{ sId: 'timer1', iFinished: Date.now() + 46800000 },
{ sId: 'timer2', iFinished: Date.now() + 780000}
];
// call display update
setInterval(function() {
updateTimer();
}, 333);
I belive that the setInterval code executes every 1000ms exactly, while the setTimeout waits 1000ms, runs the function, which takes some ms, then sets another timeout. So the wait period is actually greater than 1000ms.
From this post:
setTimeout or setInterval?