Why is this JavaScript eating all my memory? - javascript

So I have a wee javascript app that receives a pair of numbers from a server every minute (or whatever) and over the course of the minute it updates a div every second (or whatever) so that the value shown in the div gradually increments from the first value to the second. It's only short, I'll post the code at the bottom of the question.
The function contains two sub functions - one of them does the ajax call to update the two values, one of them updates the div contents with a value somewhere between the two values. The ajax function uses setInterval to schedule the div updating function when it has the response from the server, and when the div updating function detects that it's time to update the two values it clears the set interval and calls the ajax function. These two functions thus carry on calling each other for ever.
I declared every variable used by the two sub functions in the outer function, so neither sub function creates any new variables, and both sub-functions are allowed to finish completely each time anyway (thanks to the setInterval in the ajax function).
The memory usage is going up almost every second, which must be every time doDivRefresh is called, but I don't understand what it's doing with new memory each time it's called - it doesn't create any variables.
Help!
/**
*
* Periodically gets the latest values for a stat and changes the contents of a
* div so that is ticks up from the previous value to the latest value
*
* #param divID
* The id of the div to update
* #param URL
* The URL that provides the values
* #param updateDivFrequency
* How often the value displayed in the div is updated, in
* miliseconds
* #param updateDataFrequency
* How often the underlying data is updated from the server, in
* seconds
*
*/
function updateStatOverPeriod(divID, URL, updateDivFrequency, updateDataFrequency)
{
var somethingDoer = new function()
{
};
var request = new XMLHttpRequest();
var currentValue = "";
var previousValue = "";
var latestValue = "";
var it = 0;
var currentTime = new Date();
var endTime = new Date().getTime();
function doDivRefresh(endTime)
{
if (currentValue != null)
{
currentValue = currentValue + it;
document.getElementById(divID).innerHTML = addCommas(parseInt(currentValue));
}
else
{
document.getElementById(divID).innerHTML = "<DIV CLASS=\"error_message\">No data</DIV>";
}
// If it's time to refresh the data end this loop and call the starting
// off method again
currentTime = new Date();
if (currentTime.getTime() >= endTime)
{
clearInterval(somethingDoer);
doAJAX();
}
}
function doAJAX()
{
// If browser supports javascript
if (window.XMLHttpRequest)
{
// Connect to the server and get the new pair of values
request = new XMLHttpRequest();
request.open('get', URL);
request.onreadystatechange = function()
{
// Once...
if (request.readyState == 4)
{
// we've got...
if (request.status == 200)
{
// the response
if (request.responseText)
{
// Parse the response and work out our iterator
previousValue = parseFloat(request.responseText.split("&")[0]);
latestValue = parseFloat(request.responseText.split("&")[1]);
if ((previousValue == 0) || (latestValue == 0))
{
it = parseFloat('0.00');
}
else
{
it = parseFloat((latestValue - previousValue) / (updateDataFrequency / updateDivFrequency));
}
// Set up the doRefreshDiv function in a loop that
// will exit and re-call this function
// once updateDataFrequency has elapsed
currentValue = previousValue;
endTime = new Date().getTime() + updateDataFrequency;
doDivRefresh(endTime);
somethingDoer = setInterval(function()
{
doDivRefresh(endTime);
}, updateDivFrequency);
alert("end of ajax response function()");
}
else
{
document.getElementById(divName).innerHTML = "<DIV CLASS=\"error_message\">Error - no data received from server</DIV>";
}
}
else
{
document.getElementById(divName).innerHTML = "<DIV CLASS=\"error_message\">Error - server returned " + request.status + "</DIV>";
}
}
};
request.send(null);
}
else
{
console.error("No window.XMLHttpRequest, does this browser support AJAX?");
}
alert("end of doAJAX()");
}
// Start
updateDataFrequency = updateDataFrequency * 1000;
doAJAX();
}

These are the first four lines corrected according to jslint.com:
function updateStatOverPeriod(divID, URL, updateDivFrequency, updateDataFrequency) {
"use strict";
var somethingDoer = function() {};
var request = new XMLHttpRequest();
Paste your code there and check for common JS errors. It seems this code was either transformed from an other language to JavaScript or somebody who is not familiar with JavaScript...
See my answer javascript memory leak for dealing with memory leaks. I still think Drip is a very good tool for finding and understanding memory leaks.

I agree that new Date() is always going to be costly. Now here as you just want this code to be executed to refresh values at regular interval can you use setTimeout("doAJAX()",2000); and you can specify the interval in milliseconds instead of checking it using a date function. That should help and in another case you can well use jquery.Ajax if you're interested because there you will be able to concentrate on your area of interest instead of dealing with XMLHttpRequest by yourself.

[head slap]
Thanks for the answers guys, but the real problem was a typo in the element calling the script. Due to a / where I meant to put a * the script was being called about once a millisecond instead of once a minute as intended!

Related

Asynchronous recursive functions in javascript

I am trying to stream mp3 data from my server to the client side. I am doing this using Ajax. The server sends 50 kilobytes per request. I wrote two functions: one that gets the mp3 data and one that plays them. The first function takes the 50 kilobytes, decodes them and stores the decoded data in an array then it calls itself recursively. The second function starts playing as soon as the first element in the array is filled with data. The problem is that this works for the first 50kilobytes only then it fails. What I want to do is keep my get_buffer function running until the server tells it no more data to send, and keep my play() function playing data until there is no more elements in the array.
Here is my two functions:
function buffer_seg() {
// starts a new request
buff_req = new XMLHttpRequest();
// Request attributes
var method = 'GET';
var url = '/buffer.php?request=buffer&offset=' + offset;
var async = true;
// set attributes
buff_req.open(method, url, async);
buff_req.responseType = 'arraybuffer';
// keeps loading until something is recieved
if (!loaded) {
change_icon();
buffering = true;
}
buff_req.onload = function() {
segment = buff_req.response;
// if the whole file was already buffered
if (segment.byteLength == 4) {
return true;
} else if (segment.byteLength == 3) {
return false;
}
// sets the new offset
if (offset == -1) {
offset = BUFFER_SIZE;
} else {
offset += BUFFER_SIZE;
}
//decodes mp3 data and adds it to the array
audioContext.decodeAudioData(segment, function(decoded) {
buffer.push(decoded);
debugger;
if (index == 0) {
play();
}
});
}
buff_req.send();
buff_seg();
}
Second function:
function play() {
// checks if the end of buffer has been reached
if (index == buffer.length) {
loaded = false;
change_icon();
if (buffer_seg == false) {
stop();
change_icon();
return false;
}
}
loaded = true;
change_icon();
// new buffer source
var src = audioContext.createBufferSource();
src.buffer = buffer[index++];
// connects
src.connect(audioContext.destination);
src.start(time);
time += src.buffer.duration;
src.onended = function() {
src.disconnect(audioContext.destination);
play();
}
}
The recursive call to buffer_seg is in the main body of buffer_seg, not in the callback, so it happens immediately - not, as you seem to intend, after a response is received. Second, this also means that the recursive call is unconditional when it should be based on whether the previous response indicated more data would be available. If this isn't just crashing your browser, I'm not sure why. It also means that chunks of streamed audio could be pushed into the buffer out of order.
So to start I'd look at moving the recursive call to the end of the onload handler, after the check for end of stream.
In the 2nd function, what do you intend if (buffer_seg == false) to do? This condition will never be met. Are you thinking this is a way to see the last return value from buffer_seg? That's not how it works. Perhaps you should have a variable that both functions can see, which buffer_seg can set and play can test, or something like that.

how to find dynamic dom loaded time from server response in chrome? [duplicate]

I need to get execution time in milliseconds.
I originally asked this question back in 2008. The accepted answer then was to use new Date().getTime() However, we can all agree now that using the standard performance.now() API is more appropriate. I am therefore changing the accepted answer to this one.
Using performance.now():
var startTime = performance.now()
doSomething() // <---- measured code goes between startTime and endTime
var endTime = performance.now()
console.log(`Call to doSomething took ${endTime - startTime} milliseconds`)
In Node.js it is required to import the performance class
importing performance
const { performance } = require('perf_hooks');
Using console.time: (living standard)
console.time('doSomething')
doSomething() // <---- The function you're measuring time for
console.timeEnd('doSomething')
Note: The string being passed to the time() and timeEnd() methods must match(for the timer to finish as expected).
console.time() documentations:
MDN documentation
Node.js documentation
use new Date().getTime()
The getTime() method returns the number of milliseconds since midnight of January 1, 1970.
ex.
var start = new Date().getTime();
for (i = 0; i < 50000; ++i) {
// do something
}
var end = new Date().getTime();
var time = end - start;
alert('Execution time: ' + time);
Don't use Date(). Read below.
Use performance.now():
<script>
var a = performance.now();
alert('do something...');
var b = performance.now();
alert('It took ' + (b - a) + ' ms.');
</script>
It works on:
IE 10 ++
FireFox 15 ++
Chrome 24 ++
Safari 8 ++
Opera 15 ++
Android 4.4 ++
etc, etc
console.time may be viable for you, but it's non-standard §:
This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.
Besides browser support, performance.now seems to have the potential to provide more accurate timings as it appears to be the bare-bones version of console.time.
<rant> Also, DON'T EVER use Date for anything because it's affected by changes in "system time". Which means we will get invalid results —like "negative timing"— when the user doesn't have an accurate system time:
On Oct 2014, my system clock went haywire and guess what.... I opened Gmail and saw all of my day's emails "sent 0 minutes ago". And I'd thought Gmail is supposed to be built by world-class engineers from Google.......
(Set your system clock to one year ago and go to Gmail so we can all have a good laugh. Perhaps someday we will have a Hall of Shame for JS Date.)
Google Spreadsheet's now() function also suffers from this problem.
The only time you'll be using Date is when you want to show the user his system clock time. Not when you want to get the time or to measure anything.
If you need to get function execution time on your local development machine, you can either use your browser's profiling tools, or console commands such as console.time() and console.timeEnd().
All modern browsers have JavaScript profilers built-in. These profilers should give the most accurate measurement as you do not have to modify your existing code, which could affect the function's execution time.
To profile your JavaScript:
In Chrome, press F12 and select the Profiles tab, then Collect JavaScript CPU Profile.
In Firefox, install/open Firebug, and click on the Profile button.
In IE 9+, press F12, click on Script or Profiler (depending on your version of IE).
Alternatively, on your development machine, you can add instrumentation to your code with console.time() and console.timeEnd(). These functions, supported in Firefox11+, Chrome2+ and IE11+, report on timers that you start/stop via console.time(). time() takes a user-defined timer name as an argument, and timeEnd() then reports on the execution time since the timer started:
function a() {
console.time("mytimer");
... do stuff ...
var dur = console.timeEnd("myTimer"); // NOTE: dur only works in FF
}
Note that only Firefox returns the elapsed time in the timeEnd() call. The other browsers simply report the result to the developer console: the return value of timeEnd() is undefined.
If you want to get function execution time in the wild, you will have to instrument your code. You have a couple options. You can simply save the start and end times by querying new Date().getTime():
function a() {
var start = new Date().getTime();
... do stuff ...
var end = new Date().getTime();
var dur = end - start;
}
However, the Date object only has millisecond resolution and will be affected by any OS's system clock changes. In modern browsers, there's a better option.
The better option is to use the High Resolution Time, aka window.performance.now(). now() is better than the traditional Date.getTime() in two important ways:
now() is a double with submillisecond resolution that represents the number of milliseconds since the start of the page's navigation. It returns the number of microseconds in the fractional (e.g. a value of 1000.123 is 1 second and 123 microseconds).
now() is monotonically increasing. This is important as Date.getTime() can possibly jump forward or even backward on subsequent calls. Notably, if the OS's system time is updated (e.g. atomic clock synchronization), Date.getTime() is also updated. now() is guaranteed to always be monotonically increasing, so it is not affected by the OS's system time -- it will always be wall-clock time (assuming your wall clock is not atomic...).
now() can be used in almost every place that new Date().getTime(), + new Date andt Date.now() are. The exception is that Date and now() times don't mix, as Date is based on unix-epoch (the number of milliseconds since 1970), while now() is the number of milliseconds since your page navigation started (so it will be much smaller than Date).
Here's an example of how to use now():
function a() {
var start = window.performance.now();
... do stuff ...
var end = window.performance.now();
var dur = end - start;
}
now() is supported in Chrome stable, Firefox 15+, and IE10. There are also several polyfills available.
One other option for measuring execution time in the wild is UserTiming. UserTiming behaves similarly to console.time() and console.timeEnd(), but it utilizes the same High Resolution Timestamp that now() uses (so you get a sub-millisecond monotonically increasing clock), and saves the timestamps and durations to the PerformanceTimeline.
UserTiming has the concepts of marks (timestamps) and measures (durations). You can define as many of either as you want, and they're exposed on the PerformanceTimeline.
To save a timestamp, you call mark(startMarkName). To get the duration since your first mark, you simply call measure(measurename, startMarkname). The duration is then saved in the PerformanceTimeline alongside your marks.
function a() {
window.performance.mark("start");
... do stuff ...
window.performance.measure("myfunctionduration", "start");
}
// duration is window.performance.getEntriesByName("myfunctionduration", "measure")[0];
UserTiming is available in IE10+ and Chrome25+. There is also a polyfill available (which I wrote).
To get precise values you should use Performance interface. It's supported in modern versions of Firefox, Chrome, Opera and IE. Here's an example of how it can be used:
var performance = window.performance;
var t0 = performance.now();
doWork();
var t1 = performance.now();
console.log("Call to doWork took " + (t1 - t0) + " milliseconds.")
Date.getTime() or console.time() are not good for measuring precise execution time. You can use them if quick rough estimate is OK for you. By rough estimate I mean you can get 15-60 ms shift from the real time.
Check this brilliant post on measuring execution time in JavaScript. The author also gives a couple of links about accuracy of JavaScript time, worth reading.
Use Firebug, enable both Console and Javascript. Click Profile. Reload. Click Profile again. View the report.
A simple solution, you can use add operator also here
var start = +new Date();
callYourFunctionHere();
var end = +new Date();
var time = end - start;
console.log('total execution time = '+ time + 'ms');
process.hrtime() is available within Node.js - it returns a value in nanoseconds
let hrTime = process.hrtime()
console.log(hrTime[0] * 1000000 + hrTime[1] / 1000)
Here's a decorator for timing functions
It wraps functions so that they get timed each time they get run
Usage:
let test = () => { /* does something */ }
test = timed(test) // turns the function into a timed function in one line
test() // run your code as normal, logs 'function test took 1001.900ms'
This is the decorator:
let timed = (f) => (...args) => {
let start = performance.now();
let ret = f(...args);
console.log(`function ${f.name} took ${(performance.now() - start).toFixed(3)}ms`);
return ret;
}
If you're using async functions you can make timed async and add an await before f(...args), and that should work for those. It gets more complicated if you want one decorator to handle both sync and async functions.
var StopWatch = function (performance) {
this.startTime = 0;
this.stopTime = 0;
this.running = false;
this.performance = performance === false ? false : !!window.performance;
};
StopWatch.prototype.currentTime = function () {
return this.performance ? window.performance.now() : new Date().getTime();
};
StopWatch.prototype.start = function () {
this.startTime = this.currentTime();
this.running = true;
};
StopWatch.prototype.stop = function () {
this.stopTime = this.currentTime();
this.running = false;
};
StopWatch.prototype.getElapsedMilliseconds = function () {
if (this.running) {
this.stopTime = this.currentTime();
}
return this.stopTime - this.startTime;
};
StopWatch.prototype.getElapsedSeconds = function () {
return this.getElapsedMilliseconds() / 1000;
};
StopWatch.prototype.printElapsed = function (name) {
var currentName = name || 'Elapsed:';
console.log(currentName, '[' + this.getElapsedMilliseconds() + 'ms]', '[' + this.getElapsedSeconds() + 's]');
};
Benchmark
var stopwatch = new StopWatch();
stopwatch.start();
for (var index = 0; index < 100; index++) {
stopwatch.printElapsed('Instance[' + index + ']');
}
stopwatch.stop();
stopwatch.printElapsed();
Output
Instance[0] [0ms] [0s]
Instance[1] [2.999999967869371ms] [0.002999999967869371s]
Instance[2] [2.999999967869371ms] [0.002999999967869371s]
/* ... */
Instance[99] [10.999999998603016ms] [0.010999999998603016s]
Elapsed: [10.999999998603016ms] [0.010999999998603016s]
performance.now() is optional - just pass false into StopWatch constructor function.
It is possible to use only one variable:
var timer = -performance.now();
// Do something
timer += performance.now();
console.log("Time: " + (timer/1000).toFixed(5) + " sec.")
timer/1000 - to convert milliseconds to seconds
.toFixed(5) - to trim extra digits
To extend vsync's code further to have the ability to return the timeEnd as a value in NodeJS use this little piece of code.
console.timeEndValue = function(label) { // Add console.timeEndValue, to add a return value
var time = this._times[label];
if (!time) {
throw new Error('No such label: ' + label);
}
var duration = Date.now() - time;
return duration;
};
Now use the code like so:
console.time('someFunction timer');
someFunction();
var executionTime = console.timeEndValue('someFunction timer');
console.log("The execution time is " + executionTime);
This gives you more possibilities. You can store the execution time to be used for more purposes like using it in equations, or stored in a database, sent to a remote client over websockets, served on a webpage, etc.
there are multiple ways to achieve this objective :
using console.time
console.time('function');
//run the function in between these two lines for that you need to
//measure time taken by the function. ("ex. function();")
console.timeEnd('function');
this is the most efficient way :
using performance.now(), e.g.
var v1 = performance.now();
//run the function here for which you have top measure the time
var v2 = performance.now();
console.log("total time taken = "+(v2-v1)+"milliseconds");
use +(add operator) or getTime()
var h2 = +new Date(); //or
var h2 = new Date().getTime();
for(i=0;i<500;i++) { /* do something */}
var h3 = +new Date(); //or
var h3 = new Date().getTime();
var timeTaken = h3-h2;
console.log("time ====", timeTaken);
Here's what happens when you apply the unary plus operator to a Date instance:
Get the value of the Date instance in question
Convert it to a Number
NOTE: getTime() gives better performance than unary + operator.
It may help you.
var t0 = date.now();
doSomething();
var t1 = date.now();
console.log("Call to doSomething took approximate" + (t1 - t0)/1000 + " seconds.")
This is a Timer function. If you want to measure the time between multiple things that aren't nested:
function timer(lap){
if(lap) console.log(`${lap} in: ${(performance.now()-timer.prev).toFixed(3)}ms`);
timer.prev = performance.now();
}
Similar to console.time(), but easier usage if you don't need to keep track of previous timers.
Usage:
timer() // set the start
// do something
timer('built') // logs 'built in: 591.815ms'
// do something
timer('copied') // logs 'copied in: 0.065ms'
// do something
timer('compared') // logs 'compared in: 36.41ms'
If you like the blue color from console.time(), you can use this line instead
console.log(`${lap} in: %c${(performance.now()-timer.prev).toFixed(3)}ms`, 'color:blue');
Since console.time and performance.now aren't supported in some major browsers (i.e. IE10), I created a slim utility that utilizes the best available methods. However, it lacks error handling for false usages (calling End() on a not initialized timer).
Use it and improve it as you want.
Performance: {
Timer: {},
Start: function (name) {
if (console && console.time) {
console.time(name);
} else if (window.performance.now) {
this.Timer[name] = window.performance.now();
} else {
this.Timer[name] = new Date().getTime();
}
},
End: function (name) {
if (console && console.time) {
console.timeEnd(name);
} else {
var result;
if (window.performance.now) {
result = window.performance.now() - this.Timer[name];
} else {
result = new Date().getTime() - this.Timer[name];
}
console.log(name + ": " + result);
}
}
}
Use this code format
const startTime =new Date().getTime();
//do something
const endTime = new Date().getTime();
console.log(`time taken ${(endTime - startTime)/1000} seconds`);
A couple months ago I put together my own routine that times a function using Date.now() -- even though at the time the accepted method seemed to be performance.now() --
because the performance object is not yet available (built-in) in the stable Node.js release.
Today I was doing some more research and found another method for timing. Since I also found how to use this in Node.js code, I thought I would share it here.
The following is combined from the examples given by w3c and Node.js:
function functionTimer() {
performance.mark('start')
functionToBeTimed()
performance.mark('end')
performance.measure('Start to End', 'start', 'end')
const measure = performance.getEntriesByName('Start to End')[0]
console.log(measure.duration)
}
NOTE:
If you intend to use the performance object in a Node.js app, you must include the following require:
const { performance } = require('perf_hooks')
Thanks, Achim Koellner, will expand your answer a bit:
var t0 = process.hrtime();
//Start of code to measure
//End of code
var timeInMilliseconds = process.hrtime(t0)[1]/1000000; // dividing by 1000000 gives milliseconds from nanoseconds
Please, note, that you shouldn't do anything apart from what you want to measure (for example, console.log will also take time to execute and will affect performance tests).
Note, that in order by measure asynchronous functions execution time, you should insert var timeInMilliseconds = process.hrtime(t0)[1]/1000000; inside the callback. For example,
var t0 = process.hrtime();
someAsyncFunction(function(err, results) {
var timeInMilliseconds = process.hrtime(t0)[1]/1000000;
});
With performance
NodeJs: It is required to import the performance class
var time0 = performance.now(); // Store the time at this point into time0
yourFunction(); // The function you're measuring time for
var time1 = performance.now(); // Store the time at this point into time1
console.log("youFunction took " + (time1 - time0) + " milliseconds to execute");
Using console.time
console.time('someFunction');
someFunction(); // Whatever is timed goes between the two "console.time"
console.timeEnd('someFunction');
Use console.time('some label here') before the function and console.timeEnd('some label here') after the function. It will give you the running time of the function.
Stopwatch with cumulative cycles
Works with server and client (Node or DOM), uses the Performance API.
Good when you have many small cycles e.g. in a function called 1000 times that processes 1000 data objects but you want to see how each operation in this function adds up to the total.
So this one uses a module global (singleton) timer. Same as a class singleton pattern, just a bit simpler to use, but you need to put this in a separate e.g. stopwatch.js file.
const perf = typeof performance !== "undefined" ? performance : require('perf_hooks').performance;
const DIGITS = 2;
let _timers = {};
const _log = (label, delta?) => {
if (_timers[label]) {
console.log(`${label}: ` + (delta ? `${delta.toFixed(DIGITS)} ms last, ` : '') +
`${_timers[label].total.toFixed(DIGITS)} ms total, ${_timers[label].cycles} cycles`);
}
};
export const Stopwatch = {
start(label) {
const now = perf.now();
if (_timers[label]) {
if (!_timers[label].started) {
_timers[label].started = now;
}
} else {
_timers[label] = {
started: now,
total: 0,
cycles: 0
};
}
},
/** Returns total elapsed milliseconds, or null if stopwatch doesn't exist. */
stop(label, log = false) {
const now = perf.now();
if (_timers[label]) {
let delta;
if(_timers[label].started) {
delta = now - _timers[label].started;
_timers[label].started = null;
_timers[label].total += delta;
_timers[label].cycles++;
}
log && _log(label, delta);
return _timers[label].total;
} else {
return null;
}
},
/** Logs total time */
log: _log,
delete(label) {
delete _timers[label];
}
};
The best way would be to use the performance hooks module. Although unstable, you can mark specific areas of your code and measure the duration between marked areas.
const { performance, PerformanceObserver } = require('perf_hooks');
const measures = []
const obs = new PerformanceObserver(list => measures.push(...list.getEntries()));
obs.observe({ entryTypes: ['measure'] });
const getEntriesByType = cb => cb(measures);
const doSomething = val => {
performance.mark('beginning of the process');
val *= 2;
performance.mark('after multiplication');
performance.measure('time taken', 'beginning of the process', 'after multiplication');
getEntriesByType(entries => {
entries.forEach(entry => console.log(entry));
})
return val;
}
doSomething(4);
Try here
export default class Singleton {
static myInstance: Singleton = null;
_timers: any = {};
/**
* #returns {Singleton}
*/
static getInstance() {
if (Singleton.myInstance == null) {
Singleton.myInstance = new Singleton();
}
return this.myInstance;
}
initTime(label: string) {
this._timers[label] = Date.now();
return this._timers[label];
}
endTime(label: string) {
const endTime = Date.now();
if (this._timers[label]) {
const delta = endTime - this._timers[label];
const finalTime = `${label}: ${delta}ms`;
delete this._timers[label];
return finalTime;
} else {
return null;
}
}
}
InitTime related to string.
return Singleton.getInstance().initTime(label); // Returns the time init
return Singleton.getInstance().endTime(label); // Returns the total time between init and end
In my case, I perfer to use # grammar suger and compile it with babel.
The problem of this method is that function has to be inside object.
Sample JS Code
function timer() {
return (target, propertyKey, descriptor) => {
const start = Date.now();
let oldFunc = descriptor.value;
descriptor.value = async function (){
var result = await oldFunc.apply(this, arguments);
console.log(Date.now() - start);
return result;
}
}
}
// Util function
function delay(timeout) {
return new Promise((resolve) => setTimeout(() => {
resolve();
}, timeout));
}
class Test {
#timer()
async test(timout) {
await delay(timout)
console.log("delay 1");
await delay(timout)
console.log("delay 2");
}
}
const t = new Test();
t.test(1000)
t.test(100)
.babelrc (for babel 6)
{
"plugins": [
"transform-decorators-legacy"
]
}
To start the timer use console.time("myTimer");
Optional: To print the elapsed time, use
console.timeLog("myTimer");
Finally, to stop the timer and print the final
time: console.timeEnd("myTimer");
You can read more about this on MDN and in the Node.js documentation.
Available on Chrome, Firefox, Opera and NodeJS. (not on Edge or Internet Explorer).
Note: Simplest implementation of pure functional, ES6 method, no extra variables needed, just 3 lines of codes. Handles sync and async codes, so no external libraries needed, works in both JavaScript and Node JS, can even use to test the latency of your APIs
// Create one-liner timer function
let [timer, timingMonitor] = [0, () => timer = !timer ? Date.now() : `${Date.now() - timer}ms`]
// Initiate timer
timingMonitor();
// Your code here
doSomething();
// End timer
console.log(timingMonitor());
// Console output: "102ms", for example
Basic TypeScript example that supports marks. Calling start('something') will begin the timer and stop('something') will end the timer and return a formatted string containing elapsed time.
View Flems Example
/**
* Mark entries
*/
export const marks: { [id: string]: number } = {};
/**
* Start timing
*/
export const start = (id: string) => {
return Object.assign(marks, {[id]: Date.now() })[id]
}
/**
* Clear all
*/
export const clear = () => {
for (const id in marks) delete marks[id];
};
/**
* Stop timing and return formatted elapsed time
*/
export const stop = (id: string) => {
const ms = Date.now() - marks[id];
delete marks[id];
return ms > 1000
? `${(ms / 1000).toFixed(0)}s ${+ms.toFixed(0).slice(1)}ms`
: `${ms.toFixed(0)}ms`;
};
The example code is exporting each function. You can drop this into a project and call the methods accordingly from a default as import, eg:
import * as time from './timer.js'
time.start('foo')
// do something
console.log('elapsed time: ' + time.stop('bar'))
As previously stated check for and use built in timer. But if you want or need to write your own here is my two cents:
//=-=|Source|=-=//
/**
* JavaScript Timer Object
*
* var now=timer['elapsed']();
* timer['stop']();
* timer['start']();
* timer['reset']();
*
* #expose
* #method timer
* #return {number}
*/
timer=function(){
var a=Date.now();
b=0;
return{
/** #expose */
elapsed:function(){return b=Date.now()-a},
start:function(){return a=Date.now()},
stop:function(){return Date.now()},
reset:function(){return a=0}
}
}();
//=-=|Google Advanced Optimized|=-=//
timer=function(){var a=Date.now();b=0;return{a:function(){return b=Date.now()-a},start:function(){return a=Date.now()},stop:function(){return Date.now()},reset:function(){return a=0}}}();
Compilation was a success!
Original Size: 219 bytes gzipped (405 bytes uncompressed)
Compiled Size: 109 bytes gzipped (187 bytes uncompressed)
Saved 50.23% off the gzipped size (53.83% without gzip
The accepted answer is wrong !
Since JavaScript is asynchronous, the values of the variable end of the accepted answer would be wrong.
var start = new Date().getTime();
for (i = 0; i < 50000; ++i) {
// JavaScript is not waiting until the for is finished !!
}
var end = new Date().getTime();
var time = end - start;
alert('Execution time: ' + time);
The execution of the for may be very fast so you can not see that the result is wrong. You can test it with a code doing some request :
var start = new Date().getTime();
for (i = 0; i < 50000; ++i) {
$.ajax({
url: 'www.oneOfYourWebsites.com',
success: function(){
console.log("success");
}
});
}
var end = new Date().getTime();
var time = end - start;
alert('Execution time: ' + time);
So the alert will prompt very quickly but in the console you'll see that the ajax requests are continuing.
Here is how you should do it : https://developer.mozilla.org/en-US/docs/Web/API/Performance.now

forever scroll loading content dynamically with array

I have this code, and it works fine, problem is it keeps loading the content over and over again which yes I want but at the same time I don't. I want each time scroll to bottom a new page is loaded. Basically I am trying to create a Forever Scroll for my members list. The urls are the same except an integer which are split by 28s 0-28-56-84 so and so forth.
Code is
function yHandler () {
var wrap = document.getElementById('members_wrapper');
var contentHeight = wrap.offsetHeight;
var yOffset = window.pageYOffset;
var y = yOffset + window.innerHeight;
if (y >= contentHeight) {
$.get('/memberlist?mode=lastvisit&order=DESC&start=28&username',function(data) {
var elems= $(data);
$('#members_wrapper').append(elems.find('#members_wrapper'));
},'html');
}
}
window.onscroll = yHandler;
To be honest I am not quite sure how to go about this... I'm sure I could do the following,
var number = ["28","56","84"];
for (var i = 0; i>number.length; i++) {
var url = '/memberlist?mode=lastvisit&order=DESC&start='+ number[i] +'&username'
}
Then in turn I could post in like so $.get(url, function(data) {
If this would work let me know, because the next issue would be, what if I have more than 84 members and one day go up to 200+ members? Would I then in turn do a mathematical equation, which I never have done so let me explain ...
if number has already passed + 28;
Yes I know that is incorrect since I don't know how to go about this per say. Basically what I need really is if the url has already been passed add 28 to it and then pass the next url once page scroll down.
The window.onscroll handler will fire multiple times before the AJAX request has pulled in the content, which means you will fire multiple AJAX requests.
Keep track of when you are requesting the member list and don't run the onscroll handler if the AJAX request is still processing.
var fetchingContent = false; // tracks if an AJAX request is active
function yHandler () {
var wrap = document.getElementById('members_wrapper');
var contentHeight = wrap.offsetHeight;
var yOffset = window.pageYOffset;
var y = yOffset + window.innerHeight;
if (y >= contentHeight && !fetchingContent) {
// set to TRUE before AJAX request
fetchingContent = true;
$.get('/memberlist?mode=lastvisit&order=DESC&start=28&username',function(data) {
var elems= $(data);
$('#members_wrapper').append(elems.find('#members_wrapper'));
// set to FALSE after AJAX request complete
fetchingContent = false;
},'html');
}
}
window.onscroll = yHandler;
EDIT
To load the appropriate start value in the url you need to keep a reference to it.
var start = 0, limit = 28;
// once the AJAX request has finished you can update the start value
// notice the start variable is dynamically added to the AJAX url
$.get('/memberlist?mode=lastvisit&order=DESC&start='+start+'&username',function(data) {
var elems= $(data);
$('#members_wrapper').append(elems.find('#members_wrapper'));
// set to FALSE after AJAX request complete
fetchingContent = false;
// add to the start value for the next AJAX request
start = start + limit;
},'html');
The problem with doing this client side is that you don't know when the total amount of users has been reached. So you need to check for a false response.
Server Side
$response = array();
if (no members found with given start value) {
$response['success'] = 0;
} else {
$html = {get members and build div}
$response['success'] = 1;
$response['html'] = $html;
}
// send JSON back to the client
echo json_encode($response);
Now you need to check for the success parameter in the AJAX response. Notice I changed the $.get datatype to json. You could also use $.getJSON instead.
$.get('/memberlist?mode=lastvisit&order=DESC&start='+start+'&username',function(response) {
if (response.success === 1) {
var elems= $(response.html);
$('#members_wrapper').append(elems.find('#members_wrapper'));
// set to FALSE after AJAX request complete
fetchingContent = false;
// add to the start value for the next AJAX request
start = start + limit;
}
},'json');

Facebook server time in javascript

Im trying to show on my site changeable clock synchronized with facebook server.
The fb server time is available at:
https://api.facebook.com/method/fql.query?query=SELECT+now%28%29+FROM+link_stat+WHERE+url+%3D+%271.2%27&format=json
How to make it changeable every second without refreshing the page?
Assuming some non-written functions, it should look like that:
var requestBegin = Date.now();
getServertimeFromFacebook(function callback(fbTime) {
var requestEnd = Date.now();
var latency = (requestEnd - requestBegin) / 2;
var curDevicetime = Date.now(); // = requestEnd, of course
var difference = fbTime - latency - curDeviceTime;
function clock() {
var cur = Date.now();
var curFbTime = cur + difference;
show(curFbTime); // print, log, whatever
};
setInterval(clock, …); // you could use a self-adjusting clock
// by using a setTimeout for each tick
});
You could do
show = function(t) { console.log(new Date(t).toString()); };
getServertimeFromFacebook = function(cb) {
ajax("https://api.facebook.com/method/fql.query?query=SELECT+now%28%29+FROM+link_stat+WHERE+url+%3D+%271.2%27&format=json", function(responsetext) {
var obj = JSON.parse(responsetext);
var ts = obj[0].anon,
tms = ts * 1000;
cb(tms);
});
};
I wouldn't call the API every second.
Instead, I would get the Facebook server time only one time at the beginning. And then, I would increment my time value every second by looping using javascript :
setTimeout(function() { /* increment time */ }, 1000);
Bergi: [{"anon":1354654854}] is a unix time. Indeed, Facebook often (always?) deals with time using this representation.

Javascript: Set the order of functions

I'm writing a titanium app but I'm having an issue with the execution order of my javascript.
I have an event listener on a button. It's a reload button that clears a table, uses HTTPClient to GET a JSON array of 'appointments', saves each appointment, and refreshes a table list. The problem is I am executing the table delete first which should clear the table, then I get the appointments but when the app refreshes the datatable it's like it's doing it too soon and the new appointments haven't been saved yet because I'm getting an empty list. Now if I comment out the db.deleteAll line, each time I click reload the list is refreshed with the new (and existing) appointment data.
I need to make sure everything is done in order and only when the previous task is dfinished. So appointments.download() has to be executed AFTER db.DeleteAll and the list refresh has to be executed AFTER var allAppointments = db.All();
I think the problem is that the appointments.download() function has to make a HTTP GET call and then save the results and the other functions are not waiting until it's finished.
Here is the code:
btnReload.addEventListener('click', function(e){
var affected = db.deleteAll();
appointments.download();
var allAppointments = db.all();
Ti.API.info(allAppointments);
appointmentList.setData(allAppointments);
});
Here are the functions that are being called:
db.deleteAll():
api.deleteAll = function(){
conn.execute('DELETE FROM appointments');
return conn.rowsAffected;
}
appointments.download():
var appointments = (function() {
var api = {};
api.download = function(){
var xhr = Titanium.Network.createHTTPClient();
xhr.onload = function()
{
var data = JSON.parse(this.responseText);
var dl = (data.length);
for(i=0; i<dl;i++)
{
//p = addRow(data,i); // returns the **arr array
//Ti.API.info('Saving : '+data[i].first_name);
var contact_name = data[i].first_name + ' ' + data[i].last_name;
var start_date = data[i].start_date;
var reference = data[i].reference;
var comment = data[i].comment;
var appointment_id = data[i].quote_id;
var lastid = db.create(appointment_id, start_date, reference, contact_name, comment);
//Ti.API.info(lastid);
}
};
xhr.open('GET','http://********.co.uk/appointments/download/');
xhr.send();
return;
}
Any help most appreciated!
Billy
Synchronous calls give you coordination (code won't execute until any computation it depends on finishes) for free. With asynchronous calls, you have to take care of coordination. This generally means passing the dependent code as a function to the asynchronous code. The passed code is known as a "continuation", which means "the rest of the calculation, from a given point forward". Passing continuations around is known as (unsurprisingly) "continuation passing style".
To rewrite code in CPS, identify the point(s) where you need to coordinate the code (the call to appointments.download), then wrap the rest of the code in a function.
btnReload.addEventListener('click', function(e){
var affected = db.deleteAll();
appointments.download();
function () {
var allAppointments = db.all();
Ti.API.info(allAppointments);
appointmentList.setData(allAppointments);
}
});
In the general case, the return value becomes the argument to the continuation. Here, no return value for appointments.download is used, so the continuation takes no arguments.
Next, rewrite the asynchronous function to take the continuation and pass the continuation in the call.
btnReload.addEventListener('click', function(e){
var affected = db.deleteAll();
appointments.download(
function () {
var allAppointments = db.all();
Ti.API.info(allAppointments);
appointmentList.setData(allAppointments);
});
});
...
api.download = function(_return){
var xhr = Titanium.Network.createHTTPClient();
xhr.onload = function() {
var data = JSON.parse(this.responseText);
var dl = (data.length);
for (i=0; i<dl;i++) {
//p = addRow(data,i); // returns the **arr array
//Ti.API.info('Saving : '+data[i].first_name);
var contact_name = data[i].first_name + ' ' + data[i].last_name;
var start_date = data[i].start_date;
var reference = data[i].reference;
var comment = data[i].comment;
var appointment_id = data[i].quote_id;
var lastid = db.create(appointment_id, start_date, reference, contact_name, comment);
//Ti.API.info(lastid);
}
_return();
};
xhr.open('GET','http://********.co.uk/appointments/download/');
xhr.send();
return;
}
The continuation is named _return because the return statement can be modeled as a continuation (the default continuation). Calling _return in the asynchronous version would have the same affect as calling return in the synchronous version.
Currently you are making requests asynchronously which means you make a request and return from the function immediately, you don't wait for an answer. You should make your calls synchronous, I don't know what your conn and xhr really are but they might provide ways to make the execute() and send() methods synchronous. For example if you set the third argument of JavaScript's own XMLHttpRequest's open() method to false then send() method will not return until a response is received from the server, your connection classes might have the same option.
Move the call to delete the current appointments into the onload handler. That way you will delete the old and immediately add the new data.

Categories

Resources