The following code is from 'JavaScript by Example Second Edition',I think the code below is better
function scroller() {
str = str.substring(1, str.length) + str.substring(0, 1);
document.title = str;
window.status = str;
}
setInterval(scroller, 300);
The old code is recursive and will continue to call itself every 0.3 seconds until the program ends, I think the old code maybe cause stack overflow, right?
<html>
<!-- This script is a modification of a free script found at
the JavaScript source.
Author: Asif Nasir (Asifnasir#yahoo.com)
-->
<head>
<script type="text/javascript">
var today = new Date();
var year = today.getFullYear();
var future = new Date("December 25, " + year);
var diff = future.getTime() - today.getTime();
// Number of milliseconds
var days = Math.floor(diff / (1000 * 60 * 60 * 24));
// Convert to days
var str =
"Only " + days + " shopping days left until Christmas!";
function scroller() {
str = str.substring(1, str.length) + str.substring(0, 1);
document.title = str;
window.status = str;
setTimeout(scroller, 300); // Set the timer
}
</script>
</head>
<body onload="scroller()">
<b>
<font color="green" size="4">
Get Dizzy. Watch the title bar and the status bar!!
<br />
<image src="christmasscene.bmp">
</font>
</body>
</html>
setInterval is good if you don't care too much about accuracy, e.g. polling for some condition to be met.
setTimeout is good if you want a one–off event or need to adjust the interval between calls, e.g. a clock that should update as close as possible to just after the next whole second.
Both can be used for events that run continuously at approximately the specified interval, both can be cancelled, both only run at about (as soon as possible after) the designated time interval.
Incidentally, the first code example in the OP should not cause a stack overflow, though it is otherwise not very well written.
Have a look here:
'setInterval' vs 'setTimeout'
setTimeout runs the code/function once after the timeout.
setInterval runs the code/function in intervals, with the length of
the timeout between them.
For what you're doing, you should be using setInterval.
Related
I am learning javascript and at the same time trying to create a simple script that allows you to type a foreign language on a web browser with your keyboard.
So, when you type a for example, there is a single letter mapped to a, so a single character Դ would appear, however to make a character like 厄 appear, you have to type twice, since this language has more characters than the English alphabet.
So, the problem is with that last character. Normally, I should have to type g and h consecutively in the span of one second to produce the 厄 letter, but I have problems waiting to check if within two characters have been typed within one second of eachother inorder to show that letter.
So, I don't think time interval functions are the way to go about this, but I can't see any other method also.
cautions: check key whether up in keydown() & notify keydown the key is upped in keypress();
var start = null;
$('#in').keydown(function (e) {
if (!start) {//checking is a new user input
start = $.now();
}
}).keyup(function (e) {
var timeElapsed = $.now() - start;
start = null;//start the next timing tracking
console.log(['time elapsed:', timeElapsed, 'ms'].join(' '));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label>
<h2>please input some letter to test</h2>
<input id="in"/>
</label>
another answer about your question,perhaps this is your truly answer.
function duration(timestamps) {
var last = timestamps.pop();
var durations = [];
while (timestamps.length) {
durations.push(last - (last = timestamps.pop()));
}
return durations.reverse();
}
function display(mills) {
if (mills > 1000)
return (mills / 1000) + ' s';
return mills + ' ms';
}
var durations = [];
$('#in').keydown(function (e) {
durations.push($.now());
}).keyup(function (e) {
var current = durations;
current.push($.now());
durations = [];
var timeElapsed = current[current.length - 1] - current[0];
console.log([
['time elapsed:', display(timeElapsed)].join(' '),
['keys duration:', duration(current).map(display)].join(' ')
].join(' --- '));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label>
<h2>Please input something to test!</h2>
<input id="in"/>
</label>
Below is the sample code to measure the elapsed time between any 2 events.
I added setTimeout just to give you an example.
var startTime = Date.now();
setTimeout(function(){
var elapsedTime = Date.now() - startTime;
console.log('elapsedTime ='+elapsedTime);
}, 100);
Like Alex mentioned, for every press, simply store new Date().getTime(); in a variable, which will get you the latest UTC time. UTC time is given in milliseconds, so on the next key-press, just see if the current time and the stored time differ by 1000!
I have four '.dist' elements. They have a different preloaded data (exactly: 57 , 27 , 17 , 244). I want to animate incrementing, and I wrote this code:
$('.dist').each(function() {
var count = parseInt($(this).text())
var incr = 0
var that = $(this)
var animation_time = 500
var interv = animation_time / count
$(this).text('0')
var fd = setInterval(function() {
if (incr < count){
incr++
that.text(parseInt(incr))
}
} , interv)
console.log(interv)
})
The problem: The biggest value finishes 100 light years after the rest.
Console.log (directly from this code) returns:
8.928571428571429
18.51851851851852
29.41176470588235
2.0491803278688523
Thats the values which I/We expected, but I think every interval has a specific delay, but I dont't know how to detect and correct that delay.
I want to finish all of incrementations from 0 to 'var count' in time ~= 500ms. I want to start all of incrementations in the same time, and finish every one in the same time.
Sorry for my primitive querstion but I started my adventure with js/jq only 6 months ago, and I can't find the answer by google. Maybe I'm retarted or something. Thanks for help.
edit: html
<div class="info back2 border corners1">
<span class="dist">56</span> seriali<br>
<span class="dist">27</span> obejrzanych<br>
<span class="dist">17</span> oczekuje<br>
<span class="dist">244</span> sezonów<br>
</div>
You have two problems: One is that you end up with a very small interval, and second that the calculated interval becomes a float. SetInterval can only handle whole milliseconds, not fractions, so your calculation will always be off. Better to set a start and end time and calculate the difference.
This is the most accurate way to do time calculations in Javascript anyways.
$('.dist').each(function() {
var count = parseInt($(this).text());
var incr = 0;
var that = $(this);
var animation_time = 500;
$(this).text('0');
var time_start = new Date();
var fd = setInterval(function() {
var time_passed = new Date() - time_start;
if (time_passed >= animation_time) {
clearInterval(fd);
time_passed = animation_time;
}
that.text(Math.round(count*time_passed/animation_time));
} , 10);
})
http://jsfiddle.net/xau91msr/
Or if you don't care about the actual time for the animation and want browser stutters etc to not count as passed time you can increment time_passed yourself:
http://jsfiddle.net/jevjyf3m/
If you have a fixed number of steps and increment proportionally, then your counts will reach their ends together, also don't forget to clear the interval once the animation is complete.
http://jsfiddle.net/rtvtdasz/10
clearInterval(fd);
What I want should be very simple I think, but I end up with too complex situations if I search here, or on Google.
<script language="javascript">
// putten tellen
$(document).ready(function () {
$("input[type='number']").keyup(function () {
$.fn.myFunction();
});
$.fn.myFunction = function () {
var minute_value = $("#minute").val();
var second_value = $("#second").val();
if ((minute_value != '')) {
var productiesec_value = (1 / (parseInt(minute_value) * 60 + parseInt(second_value)));
var productiemin_value = productiesec_value * 60;
var productieuur_value = productiesec_value * 3600;
var productiedag_value = productiesec_value * 86400;
var productieweek_value = productiesec_value * 604800;
var productiemaand_value = productiesec_value * 2629700;
var productiejaar_value = productiesec_value * 31556952;
productiesec_value = (productiesec_value).toFixed(5);
productiemin_value = (productiemin_value).toFixed(2);
productieuur_value = (productieuur_value).toFixed(2);
productiedag_value = (productiedag_value).toFixed(0);
productieweek_value = (productieweek_value).toFixed(0);
productiemaand_value = (productiemaand_value).toFixed(0);
productiejaar_value = (productiejaar_value).toFixed(0);
$("#productiesec").val(productiesec_value.toString());
$("#productiemin").val(productiemin_value.toString());
$("#productieuur").val(productieuur_value.toString());
$("#productiedag").val(productiedag_value.toString());
$("#productieweek").val(productieweek_value.toString());
$("#productiemaand").val(productiemaand_value.toString());
$("#productiejaar").val(productiejaar_value.toString());
}
};
});
</script>
The thing I'd like to accomplish is:
Calculate the production time of a gem in multi-types of time (seconds, minutes, hours etc.) - (Done)
Calculate the production of gems by multiple pits.
Preview: http://hielke.net/projecten/productie/edelsteenput.htm
The idea is that you fill in the minutes in the first field and the seconds in the second field. Then the script should count the production in seconds, minutes, hours etc. on the right side.
After that it must be possible to fill in the second row of minutes and seconds and then counts the total production time. The same for the rest of the rows.
Welcome to SO!
A caveat about your setup: whenever possible, avoid having elements share IDs on your page. IDs are generally for elements which only occur once on your page; otherwise use a class. This practice is why document.getElementById() returns a single element, while document.getElementsByClassName() returns an array, which makes the answer to your question as easy as getting that array's .length.
This being said -- counting the number of elements with the same ID in Javascript is generally considered invalid, as getElementById() will only return one element, and (as far as I know) there isn't a way to iterate over instances of the same ID on a page.
Try changing those IDs to class names if you can, the run a document.getElementsByClassName().length on them to get the count.
I had a task to make a progress bar and a process duration timer along with it. So, not thinking twice I did this:
<div class="mainInfo">
<div id="timer"><span id="elapsedText">0:00</span>/<span id="durationText">3:00</span></div>
<div id="progressBar"><div id="progress" style="width:0;"></div></div>
</div>
And the JS:
var time = 1000;
var duration = 180;
var $progress = $("#progress");
var $elapsedText = $("#elapsedText");
updateTime();
function updateTime() {
var elapsed = time / 1000;
$elapsedText.text(Math.floor(elapsed / 60) + ":" + Math.floor(elapsed % 60));
$progress.css('width', (elapsed * 100 / duration) + "%");
time = time + 1000;
setTimeout("updateTime()", 1000);
}
Time is actually retrieved from another variable - this ones for the demo (to illustrate that I actually have the value in miliseconds).
And it worked (not only on my PC), and still does, but the procmon shows a CPU spike on browser (chrome, ff) process when this cycle is running - 30-40% instead of regular 0,5%.
Is there a more efficient way to do this?
There is a standard function for that: SetInterval(function, delay_in_ms).
It calls a function in millisecond intervals.
Instead of
setTimeout("updateTime()", 1000);
use
setTimeout(updateTime, 1000);
The fact that you're invoking the compiler each second could really hurt performance. Passing a string to setTimeout is basically causing an eval within the setTimeout.
There is a default for that, and that is setInterval.
Be careful, the function passed as the first argument to setInterval is always executed in global scope.
Number two, a progress bar is usually created along-side expensive processes. You are using it for display purposes only and forcing a delay, which I don't particularly find useful, but if you like the layout, I guess you can go for it.
The way you would usually use it is:
executeFirstPotentiallyExpensiveProcess();// this is a call to a big function.
// then update the value of the progress bar in percentage style.
executeSecondPotentiallyExpensiveFunction()// this is the second part of your process.
// then again update..
// repeat until you have 100%.
// Basically, you logically divide the expenses of your various executions
// into numerable bits, preferably equal to one another for your convenience,
// but you chunk your loading process or whatever type of process and increment
// the progress after each chunk is complete.
Your use of jQuery disturbs me...
var time = 1000;
var duration = 180;
var $progress = document.getElementById("progress");
var $elapsedText = document.getElementById("elapsedText");
var beginTimestamp = new Date().getTime();
updateTime();
setInterval(updateTime,1000);
function updateTime() {
var now = new Date().getTime();
var elapsed = now-beginTimeStamp + time;
$elapsedText.firstChild.nodeValue = Math.floor(elapsed / 60) + ":" + Math.floor(elapsed % 60);
$progress.style.width = (elapsed * 100 / duration) + "%";
}
Maybe without jQuery your browser might run better ;)
Try with the function setInterval.
I'm looking into the speed of JavaScript parsers in web browsers, importantly it needs to be easy to demonstrate. I came up with a simple test - the idea being that each script block is parsed and executed individually, so a large block of script could be timed:
<script>var start = new Date().getTime();</script>
<script>
/*! jQuery v1.8.2 jquery.com | jquery.org/license */
...
</script>
<script>alert ( new Date().getTime() - start );</script>
Superficially this appears to work, removing the middle script block will result in a negligible time.
However I'm not certain that my logic is not fundamentally flawed.
It seems the answer is broadly yes, but to get a reasonable result (like anything else) the test should be run many times to level out the effects of compilation caching and garbage collection. The test above can easily be placed into the Parse-n-Load library: http://carlos.bueno.org/2010/02/measuring-javascript-parse-and-load.html
Thanks for your help
This may be of help!
var start = new Date().getTime();
var end = new Date().getTime();
var time = end - start;
alert('Execution time: ' + time);
If you want to benchmark your JavaScript, include MilliSeconds etc.
var t = new Date();
var start = t.getTime()*1000 + t.getMilliseconds();
/* do something*/
var t2 = new Date();
var end = t2.getTime()*1000 + t.getMilliseconds();
alert("The Code needed " + (end-start) + " milliseconds. That are " + parseInt((end-start)/1000) + " seconds.");
You might want to differentiate between parsing and execution time. You could do something like
<script>start = Date.now();</script>
<script>
parsed = Date.now();
/*! jQuery v1.8.2 jquery.com | jquery.org/license */
…
</script>
<script>var end = Date.now();
alert ( "parsed in " + (parsed - start) + "ms" );
alert ( "executed in " + (end - parsed) + "ms" );
alert ( "overall time: " + (end - start) + "ms" );
</script>
With that you might be able to detect cached parse trees etc. Yet, for more distinct information have a look at your developer tools, they show such type of information in their profiler section. Or in Opera, it's included in the load process of scripts in the network panel.
This answer is from 10 years in the future.
There are a number of approaches to timing web page processes including:
Date-related methods:
Date.now();
and:
console.time-related methods:
console.time('myTimer');
console.timeLog('myTimer');
console.timeEnd('myTimer');
but, since late 2015, the ideal way to time web page processes using high-resolution timestamps has been:
window.performance.now();
Using Performance:
The Performance interface, accessed via window.performance has numerous methods, including:
timeOrigin
mark
measure
getEntries
toJSON
and more.
But in order to time a script, all you need is window.performance.now():
let scriptStart = window.performance.now();
let scriptEnd = window.performance.now();
let scriptDuration = (scriptEnd - scriptStart);
Working Example:
let paragraph = document.querySelector('p');
let button = document.querySelector('button');
const runTimedScript = () => {
let scriptStart = window.performance.now();
for (let i = 0; i < 10000; i++) {
paragraph.textContent = 'Loop iteration ' + (i + 1);
}
let scriptEnd = window.performance.now();
let scriptDuration = (scriptEnd - scriptStart);
button.textContent = 'Re-run Script';
console.log('The script ran in ' + scriptDuration + ' milliseconds');
}
button.addEventListener('click', runTimedScript, false);
button {
cursor: pointer;
}
<p></p>
<button type="button">Run Script</button>
<p>To see how long the script takes to run,<br />
click the button above repeatedly.</p>
Further Reading:
To find out more about the Performance Interface, see:
Performance API (MDN)