I've modified this existing countdown timer so that I can run multiple countdown and used session to display the timer in HTML. The runCountdown function now looks like this:
runCountdown(object, param, sessionName)
object is used instead of var myCounter of the solution. param is for countdown seconds. sessionName is for storing count current second to show it in the browser dynamically.
Now I want to run several countdown timer simultaneously , thus in the Meteor app I've done something like this
Meteor.call('doCount', function(error, result) {
if ( !result < 1 ) {
counters = new Array(result);
var queryResult = ProductList.find().fetch();
for (i = 0; i < counters.length; i++) {
var diff = queryResult[i].expire - Math.floor(TimeSync.serverTime() / 1000);
runCountdown(counters[i], diff, queryResult[i]._id);
}
console.log('testing from doCount ' + counters[0]);
}
});
doCount returns the number of Countdown Timers I want to run in the browser.
Now the weird thing is that my runCountdown function inside the for loop is working properly as I can see from the browser console, which implies that counters variable is being used this function. Obviously my main objective is not to log the object but it's showing undefined.
Why is that happening?
The runCountdown function
function runCountdown(obj,param,sessionName){
obj = new Countdown({
seconds:param, // number of seconds to count down
onUpdateStatus:
function(sec){
Session.set(sessionName,sec);
console.log(Session.get(sessionName));
}, // callback for each second
onCounterEnd: function(){ alert('counter ended!');} // final action
});
obj.start();
}
You're expecting to store the obj object to be available outside then return the obj from the runCountdown function and store it in the counters[i] array item.
function runCountdown(param,sessionName){
obj = new Countdown({
seconds:param, // number of seconds to count down
onUpdateStatus:
function(sec){
Session.set(sessionName,sec);
console.log(Session.get(sessionName));
}, // callback for each second
onCounterEnd: function(){ alert('counter ended!');} // final action
});
obj.start();
return obj;}
now in your array structure store this object in the following way -
counters[i] = runCountdown(diff, queryResult[i]._id);
Related
I am new to JS.
I need an array variable which is used to display the values periodically every 1s using setInterval() inside a function.
The array variable for ex intV[] (setInterval variable) should display the values when used in console.log(intV[]); and the values should be stored in intV[].
I tried the below code,
But it didn't work.
function date() {
var currentDate = Date.now();
var val = String(currentDate).substr(8, 2);
return val;
}
var intV = [];
function mockData(v) {
var v = document.getElementById('sample');
//setInterval function
intV[v] = setInterval(date, 1000);
console.log(intV[v]);
}
When I did console.log(intV[v]);. It doesn't display the values every 1s. Instead, it gives a static value Which is not updated every 1s.
How could i store the values, which is updated every 1s in the intV[].?
Could someone please help?
Many thanks.
The setInterval method expects a function as a parameter which is run at each specified interval. All of the logic, including console.log needs to be inside of the function that you pass to setInterval. I believe the sample provided below provides what you are looking for, but you need to understand that the intV array will be populated AS the intervals occur, NOT before.
var intV = [];
function date() {
var currentDate = Date.now();
var val = String(currentDate).substr(8, 2);
intV.push(val);
console.log(intV[intV.length - 1])
}
//setInterval function
setInterval(date, 1000);
So I want to invoke addOption after I update my state, and I know that setState in React is asynchronous so I put addOption as a callback after setState completely executes:
a_method{
this.setState({
songRec: songList,
}, this.addOption);
}
However, in my addOption method, when I log out songRec I can see that it is clearly updated but its length is still 0 so the for loop is never executed.
addOption(){
const songRec = this.state.songRec;
var datalist = document.getElementById("data");
var options = '';
console.log(songRec);
console.log(songRec.length);
for (var i = 0; i < songRec.length; i++){
//some code//
}
datalist.innerHTML = options;
}
This is the output at the console. Line 86 logs songRec and line 87 logs songRec.length.
Do you know what is happening and how to get around it?
In javascript console.log does not execute immediately in the line you set it (it kinda varies on each browser), in this case, you should change it to a debugger in order to see what is really going on. Is there some specific reason to run this callback function? Can't you use the data that you set on the state to execute this other function?
The problem is mostly likely caused by the asynchronous function on array. Refer to the following example:
function asyncFunction(list){
setTimeout(function(){
list.push('a');
list.push('b');
list.push('c');
console.log(list.length); // array length is 3 - after two seconds
}, 2000); // 2 seconds timeout
}
var list=[];
//getting data from a database
asyncFunction(list);
console.log(list.length) //array is length zero - after immediately
console.log(list) // console will show all values if you expand "[]" after two secon
To fix this, a workaround you may need to use is to use a promise for the async part.
function asyncFunction(list){
return new Promise(resolve => {
setTimeout(function(){
list.push('a');
list.push('b');
list.push('c');
resolve(list);
console.log(list.length); // array length is 3 - after two seconds
}, 2000);
});
// 2 seconds timeout
}
async function getList(){
var list=[];
await asyncFunction(list);
console.log(list.length) ;
console.log(list);
}
getList();
I want to be able to make the console.log(key); make the log every 5 seconds, at the moment there is no delay and all the data gets logged at the same time.
//the location of my usres table
var ref = new Firebase('https://myapp.firebaseIO.com/users/');
//ask fire base to get the records just once
ref.once("value", function (snapshot) {
//loop through the retuned records
snapshot.forEach(function (childSnapshot) {
// get just the value for the key
var key = childSnapshot.key();
// log the key - this will be changed to send the value to another function
console.log(key);
});
})
The console.log above give me thousands of Id's, I need to pass these Id's to another function, If I pass all these id's all at one time the next function will blow up, so I want to pass them slowly, one by one to the next function. other ideas welcomed.
Use closure to get the value of key of current iteration after the setTimeout
Try this:
var ref = new Firebase('https://myapp.firebaseIO.com/users/');
ref.once("value", function(snapshot) {
snapshot.forEach(function(childSnapshot, index) {
var key = childSnapshot.key();
setTimeout((function(key) {
return function() {
console.log(key);
}
})(key), 5000 * index);
});
});
var ref = new Firebase('https://myapp.firebaseIO.com/users/');
ref.once("value", function (snapshot) {
for(var i=0; i<snapshot.lenght;i++){
var childSnapshot = snapshot[i];
var key = childSnapshot.key();
setTimeout(function () {
console.log(key);
}, 5000); // will stop the loop for 5 seconds every time
}
});
Maybe you mean a custom array iterator that iterates to the next element in the array after a specified delay. I made one using functional programming principals to promote re usability. see below
/*
* makeTimedForEach
*
* this will create an array itererator that will loop through an array
* at a specified timeout delay.
*
* #param {array} arr array to iterate
*
* #returns {Function} function to pass in callback and delay
*/
function makeTimedForEach(arr) {
return function timedForEach(fn, delay) {
var ii = 0;
function iterate() {
if (ii < arr.length) {
// call the callback injecting the current element, index and array like native forEach
fn.call( arr[ii], arr[ii], ii, arr );
ii++;
// call iterate again
setTimeout(iterate, delay);
}
}
// call for the first time you could add a setTimout here
// if you needed a delay at the start
// setTimeout( iterate, delay );
iterate();
}
}
// Snapshot mock
function Snapshot(key) {
this._key = key;
}
Snapshot.prototype = {
key: function(){
return this._key;
}
}
var
// a mock of the snapshot you get returned from `new FireBase`
snapshot = [new Snapshot('one'), new Snapshot('two'), new Snapshot('three')],
// create the iterator
snapshotTimedForEach = makeTimedForEach(snapshot);
// call the iterator passing in the callback and the delay time
snapshotTimedForEach(function(childSnapshot, ii, arr) {
console.log( childSnapshot.key(), childSnapshot, ii, arr );
}, 1000);
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>
original answer:
Im not sure if this is what you need, I cant see a point in logging the same result every 5 seconds. It seems you may want to poll the firebase api every 5 seconds
var ref = new Firebase('https://myapp.firebaseIO.com/users/');
ref.once("value", function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var key = childSnapshot.key();
// you can use setTimeout that recursively calls itself,
// setTimeout will run the callback after the time has passed
// and wont lock up your thread like setInterval
function log() {
console.log(key);
setTimeout( log, 5000);
}
// call log for the first time
setTimeout( log, 5000);
});
})
You can use setTimeout and recursive function like this:
function values(obj) {
if (obj instanceof Array) {
return obj.slice();
} else {
return Object.keys(obj).map(function(key) {
return obj[key];
});
}
}
ref.once("value", function (snapshot) {
var array = values(snapshot.val());
(function process() {
var item = array.shift();
if (item) {
var key = item.key();
console.log(key);
setTimeout(process, 5000);
}
})();
});
My question is: is there a unique way to reset timers without knowing their ID in Javascript? I tried using this code:
var maxId = setTimeout(function(){}, 0);
for(var i=0; i < maxId; i+=1) {
clearTimeout(i);
}
I'm aware this would search for any timer and clear any timer, but nothing happens and I think the console even gives me an error when I use it as a bookmarklet. Also, the value of the timer is stored in innerHTML, as such:
<div id="timer">
<div id="timer-minutes" class="timer-fields">00:00</div>
</div>
A unique way to look at this problem is to override the default functionality of setTimeout. By augmenting the function you can then tap into all uses of setTimeout on the page. Then you can simply create a new method to clear all timeouts.
In the code below, I hot-wire the built-in function (setTimeout) with my own version. As long as this code executes before other scripts on the page, I then can keep track of all invocations of the function on the page. Perhaps you could even store the setTimeouts by callee.
(function(win)
{
var _originalSetTimeout = setTimeout; //Store built-in function
var timers = []; //Maintain a collection of timers
win.setTimeout = function(func, delay) //Hijack the built-in function with your own
{
var timer = _originalSetTimeout(func, delay); //Invoke the built in
timers.push(timer); //Store the timer to your private array
};
win.clearAllTimeouts = function() //Create a new function on the window for resetting all timers
{
for(var i=0,length=timers.length;i<length;i++)
{
win.clearTimeout(timers[i]);
}
};
}(window));
Once this function is wired up you then can test with the following code:
var x=0;
function Test()
{
x++;
console.log('test: ' + x);
setTimeout(Test, 1000);
if(x === 5)
{
clearAllTimeouts();
console.log('all timeouts cleared!');
}
}
Test();
The counter will log up to 5, then once it's it the clearAllTimeouts() function is invoked.
See it in action here:
http://jsbin.com/bulayuro/1/edit
We have started a timer with the following code. Is it possible to make window.setInterval method fail, if another timer is active on the method passed to the window.setInterval method?
GInterValId = window.setInterval("AutoRefresh()",parseInt(GRefreshInterval));
what you do is set up a system for this. Create an object that handle all your Timers:
var Timer = function () {
var currentTimer;
this.setTimer = function (func,time) {
if (currentTimer) {
alert("one timer already set");
}else {
currentTimer = setInterval(func,time);
}
}
this.stopTimer = function () {
clearInterval(currentTimer);
currentTimer = null;
}
}
Now you can use this code:
function doSomething() {...} // function example
function doSomethingElse() {...} // function example
var MyTimer = new Timer();
MyTimer.setTimer(doSomething,1000); // this will run
MyTimer.setTimer(doSomethingElse,1000); // this will not run
The second one will not run because the other one is active.
to make it work you have clear the first one.
MyTimer.stopTimer(); // will clear the current timer then you can run another one
MyTimer.setTimer(doSomethingElse,1000); // will run perfectly
If you keep track of the result result from window.setInterval(), you can stop the previous interval timer at any point.
var GInterValId = setInterval(AutoRefresh, parseInt(GRefreshInterval));
Then, when you want to reset it:
if (GInterValId) {
clearInterval(GInterValId);
}
GInterValId = setInterval(AutoRefresh, parseInt(GRefreshInterval));
Also note that I'm not passing a string to setInterval, but an actual JS function reference.
Or, if you just want to prevent another interval getting set:
var GInterValId = null; // initialize
// then, when you want to set it, check to see if it's already been set
if (GInterValId) {
GInterValId = setInterval(AutoRefresh, parseInt(GRefreshInterval));
}