javascript profiling: way of showing top-down tree for individual function? - javascript

Say I have a function OfInterest, called by functions A and B, and that calls function X and Y. I'm looking for a way of viewing:
OfInterest -- 200 ms total time
X -- 150 ms total time
Y -- 50 ms total time
...such that it includes both the calls to OfInterest by A and B.
In the Chrome profiler, this would be the top-down view zoomed in on OfInterest, except that AFAIK there's no way of including calls to OfInterest from both A + B at the same time. The bottom-up view gets the right total time for OfInterest, but AFAIK there's no way of seeing X + Y in that view.
Is there a way of getting Chrome to spit this out, or using a different profiler such as Firebug to see this?

This github project gives top down tree for jvascript call stat
https://github.com/brucespang/jsprof
When i was looking for a javascript function call profiler i found a small script, which i modified as per my need, this script is very simple it will show statistics of all global functions in that window object though it doesnt list names of nested functions called.
function callLog()
{
var functionPool = {}
for( var func in window )
{
if (typeof(window[func]) === 'function')
{
functionPool[func] = window[func];
(function(){
var functionName = func;
var totalTime= 0;
var noOfTimes =0;
var minTime= 0;
var maxTime =0;
window[functionName] = function(){
var args = [].splice.call(arguments,0);
var startTime = +new Date;
functionPool[functionName].apply(window, args );
var duration = new Date - startTime;
if (duration> maxTime)
maxTime= duration;
if (duration< minTime)
minTime= duration;
totalTime = totalTime + duration;
noOfTimes++ ;
console.log('Executed: ' + functionName + '('+args.join(',')+')' + " Time[" + duration + "ms]"+" Total Time[" + totalTime +"ms]" +" No of Times[" + noOfTimes + "]" + "max Time [" + maxTime+ "ms]" + "min Time [" +minTime +"ms]");
}
})();
}
}
}

Related

How do I constantly refresh a getTime output?

I'm making a little clock using getTime(), but the output won't refresh. I have tried this:
<p id="clock"></p>
var i;
for (i=0; i < 5; i++){
var date = getTime;
var time = time.getHour() + ":" + time.getMinute() + ":" + time.getSecond()
getElementById('clock').innerHTML = time;
}
Though it just keeps my tab in a constant state of loading. How do I fix this? Thanks!
Just move your code inside setInterval()
let i = 5;
const timer = setInterval(() => {
var date = getTime;
var time = time.getHour() + ":" + time.getMinute() + ":" + time.getSecond()
getElementById('clock').innerHTML = time;
i--;
if (i < 0) {
clearInterval(timer)
}
}, 1000);
So setInterval() lets your code run asyncrounously, that means it doesnt block the rest of the execution, because it runs "seperately" (I would like to describe it better, but my english skills are lacking).
setInterval runs your code every 1000 ms (as specified) forever, unless you dont clear it with clearInterval(). If you want to make a timer it is quiet useful.
this () => {} is an arrow function. You can also use function(){}, if you want, in this case it makes no difference.
Here is the w3schools reference for setInterval(): https://www.w3schools.com/jsref/met_win_setinterval.asp
and here is the MDN reference to asynchronous javascript: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous
Good luck with your project ;)
I hope this helps
setInterval (function refresh(){
var fecha = new Date();
var hora = fecha.getHours();
var minutos = fecha.getMinutes();
var segundos = fecha.getSeconds();
var textoHora = `
${hora}:${minutos}:${segundos}
`;
document.getElementById('clock').innerHTML = textoHora;
}, 1000);

How to take lag into account using setTimeout in javascript

setTimeout(func,delay) seems to fire very precisely at the specified time, as long as the page is not running some script while it is trying to fire the function. But is there a way to take lag into account?
For example if I set a 3sec timeout and javascript runs some heavy code which makes the page leggy for a while. As long as processing the "heavy code" is done by the 3sec it will timeout after ~3sec.
Is there a way to take the "heavy code" processing time into account and timeout after 3sec + the time the page was blocked?
Here is a jsfiddle: http://jsfiddle.net/me2loveit2/mCj2J/
var timeStart = new Date().getTime();
setTimeout(test, 3000); //<-- timeout should be 100
function test() {
var timeAfter100MS = new Date().getTime();
$('body').append('Timeout Fired at: <br>' + (timeAfter100MS - timeStart) + 'ms<br> (should be ~3000, but it did not take the blocked time into account.)');
}
function block() {
for (var i = 0; i < 100000000; i++) {};
}
block();
block();
block();
var timeEnd = new Date().getTime();
$('body').append('Page was blocked(running importaint code :)) for:<br>' + (timeEnd - timeStart) + 'ms<br>');
As #adeneo pointed out, there is no such possibility. You simply can't know how effectively processor is running your code at the other end, or the tasks it is currently making which might slow it down further. Every case is different. setTimeout tries to match the specified time but very often, it just can't be exact.
I think the solution is just to change your mindset. Try to avoid long blocking synchronous operations such as for (var i = 0; i < 10000000; i++) {}; When you drop or modify these you can have more accurate setTimeout firing. The reason being, that there will be smaller executable chunks in the event queue.
Generally speaking, there are different ways to do processing of blocking events. For instance, you could look into Web workers or yielding setTimeout calls. (See links at the end of this post).
Hence, I don't know your specific case, but if you are trying to make many setTimeout calls just as in game programming (loops) solution is to try to alter future setTimeout calls to contain smaller value so the full loop will try to catch up the simulation to match the specific frame rate.
This is usually done with combination of requestAnimationFrame.
Short example of a loop which attemps to run 30 fps in the browser:
You can also view it in js fiddle
/**
* This is example to run loop with 30fps in the browser
*
*/
var gl = {
now: new Date().getTime(),
dt: 0.0,
last: new Date().getTime(),
// physics with 0.033333 steps
step: 1 / 30
},
frames = 0,
started = new Date().getTime();
/**
* Game loop
*
*/
var gameLoop = function () {
gl.now = new Date().getTime();
gl.dt = gl.dt + Math.min(1, (gl.now - gl.last) / 1000);
while (gl.dt > gl.step) {
gl.dt = gl.dt - gl.step;
// Increase frames
frames++;
if(frames === 30) {
// How long it took to execute 30 frames in 1000 ms ?
document.body.innerHTML = "We executed 30 frames in " + (new Date().getTime() - started) + " ms.";
started = new Date().getTime();
frames = 0;
}
}
// last
gl.last = gl.now;
// next
requestAnimationFrame(gameLoop);
};
// Start the game loop
gameLoop();
Hopefully, this gave you some ideas. Thus, don't forget to use css transitions and similar when those can be applied.
For further reading, I recommend:
Yielding setTimeout calls
How to avoid blocking the browser while doing heavy work
Using Web Workers
Cheers.
Not sure I understand the question 100%, but if you do something like this, you're able to see if the other stuff (heavy processing) is not done by the time the timeout runs. This should take about 5 seconds, if you switch the 2000000000 to a 20000 (less proccessing), it should come back at 3 seconds.
var timeStart = new Date().getTime();
setTimeout(test, 3000); //<-- timeout should be 100
var currentTime = new Date().getTime();
function test() {
if (currentTime - timeStart < 3000){
var timeAfter100MS = new Date().getTime();
$('body').append('Took less than 3 seconds - ' + (timeAfter100MS - timeStart)+"ms");
}else{
$('body').append('Took more than 3 seconds');
}
}
function block() {
for (var i = 0; i < 10000000; i++) {};
currentTime = new Date().getTime();
}
block();
block();
block();
var timeEnd = new Date().getTime();
$('body').append('Page was blocked(running importaint code :)) for:<br>' + (timeEnd - timeStart) + 'ms<br>');
If the 'important' code causes really significant lag, and precise timing is important, you can keep the precision by using two timeouts. The first timeout measures the lag and sets the second timeout accordingly.
Here's an example, using your code as a basis:
var timeStart = new Date().getTime();
var msDelay = 3000;
setTimeout(testLag, msDelay - 500);
function testLag() {
var timeTestLag = new Date().getTime();
$('body').append('testLag() fired at: ' + (timeTestLag - timeStart) + 'ms<br/>');
setTimeout(test, timeStart + msDelay - timeTestLag);
}
function test() {
var timeAfter100MS = new Date().getTime();
$('body').append('Timeout Fired at: <br>' + (timeAfter100MS - timeStart) + 'ms<br> (should be ~3000, but it did not take the blocked time into account.)');
}
function block() {
for (var i = 0; i < 1000000000; i++) {};
}
block();
block();
block();
block();
block();
var timeEnd = new Date().getTime();
$('body').append('Page was blocked(running importaint code :)) for:<br>' + (timeEnd - timeStart) + 'ms<br>');
Note that the block is significantly more intensive than yours - I added a zero to your 100000000, and added a couple of extra block() calls. You might need to adjust the figures to get a sensible level of block for your own machine.
Based on Mauno's Answer I came up with a solution to temporarily "track the lag" using an interval. I am setting an interval with short intervals to capture the delay and set another timeout if necessary. Here is the working example: http://jsfiddle.net/me2loveit2/mCj2J/14/
It is approximate, but always walls within 100ms of the target which is good enough for me. It could be even more accurate if I increase the interval rate, but what I got is good enough for me.
I know using timeout & interval is not the best but sometimes the only way. I am just using them for a couple of seconds on page load and that's it.
Here is the code:
var timeStart = new Date().getTime();
var aditionalTimeout = 0;
var myTimeout;
setTimer(3000);
block();
block();
block();
var timeEnd = new Date().getTime();
$('body').append('Page was blocked(running importaint code :)) for:<br>' + (timeEnd - timeStart) + 'ms<br>');
function setTimer(milliseconds) {
//allow additional time to account for the huge lag the page has on load
recoverLagTime(milliseconds);
myTimeout = setTimeout(function () {
if (!aditionalTimeout) {
test();
} else {
if (aditionalTimeout >= milliseconds) {
test();
return;
}
setTimer(aditionalTimeout);
}
}, milliseconds);
}
function recoverLagTime(timeoutTime) {
aditionalTimeout = 0;
var interval = 50;
var counter = Math.ceil(timeoutTime / interval);
var startTime = new Date().getTime();
var intervalTime;
var lagInterval = setInterval(adjustTimer, interval);
function adjustTimer() {
if (counter <= 0 || aditionalTimeout < 0) {
clearInterval(lagInterval);
return;
}
counter--;
intervalTime = new Date().getTime();
var diff = (intervalTime - startTime);
if (diff > (interval + 5)) {
aditionalTimeout += (diff - interval);
}
startTime = new Date().getTime();
}
}
function test() {
aditionalTimeout = -100;//stop the check function
var timeAfter100MS = new Date().getTime();
$('body').append('Timeout Fired at: <br>' + (timeAfter100MS - timeStart) + 'ms<br> (should be ~3000 + ~amount blocked)');
}
function block() {
for (var i = 0; i < 100000000; i++) {};
}
I wrote a small (2-file) library for exactly these purposes : running heavy code whenever the CPU has idle time (using requestAnimationFrame) by splitting the code into smaller iterations so it doesn't block the whole application by allotting a specific percentage of CPU time to execution the code, and use the remainder to execute other scripts / update UI.
It functions similarly to other answers, but might be convenient to you as you can easily calculate elapsed time between executions, if you need to know these figures (or use it to leverage operations within your application, as that's what it was written for)
https://github.com/igorski/zThreader

javascript settimeout change delay in function call

I need javascript function that runs timer and when timer expired it calls function calllink() that sets new x1 variable witch value is then passed to settimeout duration delay.
For example...here is the code:
var x1 = 5000;
function calllink() {
alert("Delayed " + x1);
x1 = 1000;
}
setTimeout(function() { calllink(); }, x1);
So when running this code it needs to delay first 5seconds then display message:
Delayed 5000 then run again setTimeout and when time expired display message Delayed 1000
I need this for programming epg, so i read xml file, read into variable x1 from xml file for channel duration (endtime - starttime) and then execute this function, when time expired it calls calllink() that then read from xml next program duration (endtime-starttime) and then sets new value of variable x1 that is set to setTimeout x1.
If is this possible to do? I was trying today, and no go. I always getting in delay of 1seconds messages.
UPDATED Question:
Ok...since i need to read epg for 130 channels in my list i put this function in onLoad:
// get epg info for all items
for (var count = 0; count <= max; count++) {
epg(count);
setEPGTimer(count);
}
// set epg
function setEPGTimer(count) {
epg(count);
setTimeout( function() { setEPGTimer(count); }, seconds[count] );
}
and json call that retrieves info about show time, start time, end time and description
// get epg
function epg(count) {
// read epg from url
$.getJSON( "http://mywebsite.com/epg.php?channel=" + epgs[count] + "&type=channel", function( data ) {
var item = [];
$.each( data, function( key, val ) {
if ( typeof (val.epg) != "undefined" && val.epg !== null) {
item.push( "<li class='epg'><b>" + count + ". " + channel[count] + "</b></br>" + val.epg.start1 + " - " + val.epg.title1 + "</li>" );
// make global variable epg description
desc[count] = val.epg.desc1;
// convert start and end time to seconds
var a1 = val.epg.start1.split(':');
var a2 = val.epg.stop1.split(':');
var seconds2 = (+a2[0]) * 60 * 60 + (+a2[1]) * 60;
var seconds1 = (+a1[0]) * 60 * 60 + (+a1[1]) * 60;
var seconds0 = (seconds2 - seconds1);
// check if is not time in minus
if (seconds0 > 0) {
seconds[count] = seconds0;
} else{
seconds[count] = 0;
}
}
});
$( ".jTscroller ul#" + count + " li.epg" ).remove();
$( "<li/>", { "class": "", html: item.join( "" ) }).appendTo( ".jTscroller ul#" + count + ".channels" );
});
}
my max variable have value 130..so I was trying to increase timer variable name to 130 (timer[0], timer[1]....timer[129] and put value of seconds[count] into that timer variable (timer[0] = seconds[0], timer[1] = seconds[1].....timer[129] = seconds[129]).
And then when time is out then calls function epg(count) that retrieves new data info for show and sets variable seconds[count] to new value, refreshed li element with new show name durataion...
So the question is how can I loop 130timers for 130channels and when one or more timers time expire it refresh that channel ul with new values?
You need to additionally add your setTimeout call into your calllink function itself, to make it recursive like this:
var x1 = 5000;
function calllink() {
alert("Delayed " + x1);
x1 = 1000;
setTimeout(function() { calllink(); }, x1);
}
setTimeout(function() { calllink(); }, x1);
Note that you should probably add some kind of conditional so that it won't repeat forever, unless that is what you want it to do.
I think this is want you want:
var x1 = getNextFromXml();
function calllink() {
alert("Delayed " + x1);
x1 = getNextFromXml();
setTimeout(calllink, x1);
};
setTimeout(calllink, x1);
Now you only have to implement the function getNextFromXml.

Looping over contents of a JSON without reloading the page

I have a JSON array(?) of pairs of every state and a value associated with that state, it looks like the following below:
var states = [{"STATE":"AL","AMOUNT":"6"}, {"STATE":"AK","AMOUNT":"3"}]
I need the page to shuffle through them without reloading the page
"AL 6" [wait x seconds] then "AK 3" [wait x seconds] then etc...
I need this to run continuously.
I never use any of these languages but was told that they were my best bet.
Could someone give me some guidance on this please.
Thank you in advance.
Here's a jsfiddle with setInterval execting a function that alternates between each state and displays it in a div:
http://jsfiddle.net/WD5Qj/1/
var states = '[{"STATE":"AL","AMOUNT":"6"}, {"STATE":"AK","AMOUNT":"3"}]';
json = jQuery.parseJSON(states);
var i = 0;
var cycle = function(){
$("#state").html(json[i].STATE + json[i].AMOUNT);
i = (i+1)%json.length;
}
var loop = setInterval(cycle, 500);
Alright, you'd need a function that does the rotation through the array, and a variable for keeping the current state (in both meanings of the word):
var stateIndex = 0;
function rotate() {
stateIndex++;
if(stateIndex >= states.length)
stateIndex = 0;
displayState(states[stateIndex]);
}
And you'd need an interval to perform the rotation:
var stateRotation = window.setInterval(rotate, 3000); // 3000ms = 3 sec
The stateRotation variable is an identifier of your interval. You may use that if you ever want to stop: window.clearInterval(stateRotation);
Now, the above code anticipates a function displayState which takes a state object and displays it. How that would look depends entirely on how you want your state to displayed. In its simplest form, something like this:
function displayState(state) {
$('#state-name').html(state.STATE);
$('#state-amount').html(state.AMOUNT);
}
As per your description, it might perhaps be something more like
$('#state-text').html(state.STATE + ' ' + state.AMOUNT);
var states = [{"STATE":"AL","AMOUNT":"6"}, {"STATE":"AK","AMOUNT":"3"}];
var i = 0;
setInterval(function(){
var array_index = i % states.length;
$('#state').html( states[ array_index ]['STATE'] );
$('#state').html( states[ array_index ]['AMOUNT'] );
i++;
}, 2000);
Here's a fiddle.
function displayNextItem(index){
if (index === states.length)
displayNextItem(0);
$("#someDiv").text(states[index]["STATE"] + " " + states[index]["AMOUNT"]);
setTimeout(function() { displayNextItem(index + 1); }, 1000);
}
And then
displayNextItem(0);
var i = 0, l = states.length, timer, intervalLength = 5000;
timer = setInterval(function(){
if(i >= l){
clearInterval(timer);
}else{
alert(states[i++].STATE);
}
},intervalLength);
This implementation is waiting the AMOUNT number of seconds. If you want constant number of seconds then other answers are better :).
JavaScript:
var states = [{"STATE":"AL","AMOUNT":"6"}, {"STATE":"AK","AMOUNT":"3"}];
function iterate(index) {
var time = states[index].AMOUNT;
// replace the text with new one
$("#output").text(states[index].STATE + " " + time);
setTimeout(function() {
var next = (index + 1) % states.length;
iterate(next);
}, time * 1000);
}
iterate(0);
HERE is the code.

JavaScript not updating before setInterval

Thanks Sean for your help. I have moved the calculation code to its own method as you suggested. After debugging I have realised the problem is something to do with storing values globally. I think I have accidently created closures. I have moved the calculation code into a method named calculate() that is run once so that the values of the variable are set globally. but while the method is running the correct values are set, as soon as the method exits and the move() method is called all the values are set to undefined or 0. In the calculate method I even used a hidden field to set the value ('mills') so that I can pass the interval time to this testTimer = window.setInterval(move,document.getElementById('mills').value,"testTimer"); Code of thecalculate()` method looks like this:-
var duration_equiv_seconds = 0;
var duration_equiv_millsec = 0;
var elapsed_percentage = 0;
var elapsed = 0;
var duration = 0;
// function in one JS file
function calculate () {
duration = document.getElementById('callDuration').value;
elapsed = document.getElementById('callElapsed').value;
duration_equiv_seconds = duration/100;
duration_equiv_millsec = duration_equiv_seconds * 1000;
document.getElementById('mills').value = Number(duration)/100 * 1000 ;
elapsed_percentage = (elapsed/duration) * 100;
display_progress(elapsed_percentage);
var countCalc = 0;
document.getElementById('status_message').innerHTML =" CountCalc = " + countCalc + " duration = " + duration + " elapsed =" + elapsed + " elapsed2Var =" + elapsed2Var +" duration_equiv_seconds = " + duration_equiv_seconds + " duration_equiv_millsec=" + duration_equiv_millsec + "
elapsed_percentage=" + elapsed_percentage; countCalc++; return duration_equiv_millsec; }
function voice_progress (time_interval){
// outer timer
voiceTimer = window.setInterval(function(){
handleDurationElapsedRequest()
// outside
function move(){
var count = 0;
duration = document.getElementById('callDuration').value;
elapsed = document.getElementById('callElapsed').value;
duration_equiv_seconds = duration/100;
duration_equiv_millsec = duration_equiv_seconds * 1000;
elapsed = Number(elapsed) + Number(duration_equiv_seconds);
elapsed_percentage = (elapsed/duration) * 100;
document.getElementById('callElapsed').value = elapsed;
display_progress(elapsed_percentage);
move_bar(elapsed_percentage);
if (elapsed_percentage >= 100){
terminate_timer(testTimer);
}
document.getElementById('status_message').innerHTML =" at the endAt the end" + count + " duration = " + duration + " elapsed =" + elapsed +" duration_equiv_seconds = " + duration_equiv_seconds + " duration_equiv_millsec=" + duration_equiv_millsec + " elapsed_percentage=" + elapsed_percentage;
count++;
return duration_equiv_millsec;
}
var sleepTime = calculate(); // sleep time returns 0
testTimer = window.setInterval(move,document.getElementById('mills').value ,"testTimer");
},time_interval,"voiceTimer"); // end of outer Timer (time_interval = 1500) called from <body onload="voice_progress(1500);">
}
//.................................................................`enter code here`
// in another JS file
// XMLHttpObject is created called, server returns the correct values
function handleDurationElapsedRequest(){
if(xmlHttpObject.readyState==4){
if(xmlHttpObject.status==200){
var resp = xmlHttpObject.responseText;
var respArray = resp.split("-");
document.getElementById('callElapsed').value = respArray[0]; //value set here is 47
document.getElementById('callDuration').value = respArray[1]; // value set here is 240
document.getElementById('mills').value = respArray[1]/100 * 1000 ;
}
}
}
The problem is that you are doing the calculations inside of your callback, so that when you start, all of your variables are still 0.
Pull the time calculation out into its own function, and call that before you call setInterval, and your values will start with the right numbers. (Continue to call it in your callback, of course.)
You also are re-scheduling your setInterval call inside move. This is probably wrong, because it will be re-called every interval, so now you have 2 functions being called on a timer. If you use setTimeout, then you might want to reschedule, but not with setInterval.
You also have the same calculation done twice -- JavaScript is real code, and you should treat it as such; Pull that out into a function you can call.
-- Edit --
Now call calculate() from move() so you don't have the same code in 2 places. ;-)
callDuration and callElapsed are only set from handleDurationElapsedRequest, and only when the request is finished. That's probably why you're getting 0. What exactly are you trying to do here? Is the whole page on line somewhere?
Thanks for help. I have fixed the problem. The problem was I was reading the values 'callDuration' and 'callElapsed' before they were even updated after they have been retrieved from the server. I fixed this by setting a timeout of 1.5 seconds before the code that reads these values is executed ie window.setTimeout("calculate()",1500);
Thanks for the help again.

Categories