Ok. I don't have a code for this question. I am asking this because I am new to javascript. I would like to know how to create a timed queue in JS. Here is the trick.
I have a combobox. The combobox has extjs data store behind and its getting updated with new data every 5 seconds, i.e the combo will get new row entries.
The row entries can be of three types 1,2 and 3. There can be several rows of same type but with different row id. Each row will be removed from the combo if there is no update for 5 minutes. This means if I get new row from the store with type 3 it will stay in the combo for 5 minutes. If the same row appears (with the same id and type) in the new data fetched the 5 minutes timer gets reset and again counts 5 minutes. And so forth.
How to achieve this functionality in javascript.
Please write comments if not understood.
Here is an example:
row_1 type1 5 min timer start
row_2 type1 5 min timer start
row_3 type3 5 min timer start
row_2 type2 5 min timer start
This is an example of the current data fetched. After 3 minutes I get this data.
row_3 type3 5 min timer start
the rest of the rows timers continue until 5 min limit is reached but for row three the timer gets reset and it will stay in the combo for the next 5 minutes.
You're going to have to keep track of two things here: The actual item, and when it was last updated (or, more accurately, the timeout event which will update it.
timeouts = [];
elems = [];
function updateElem(no){
//Do your update on elems[no]
clearTimeout(timeouts[no]);
timeouts[no] = setTimeout(function(){ removeElem(no) }, 5*60*1000 );
}
function removeElem(no){
//Remove the element.
}
This demonstrates the base concept. There are much better ways to keep everything tied together, but the basic idea is:
Set a timeout on the object to remove it after five minutes
When updating an object:
Clear the previous timeout
Set a new timeout
Because JS isn't truly multi-threaded, you don't have to worry about concurrency issues, as long as you have your scoping figured out.
Check this documentation to see how the timeout events work in a fuller sense.
Somewhere else:
function ComboRemoval(id)
{
Lookup your combobox (document.findelementbyid perhaps)
Find element with value "id"
remove it
}
When adding an element to the combo box:
Add the element
setInterval(function() { ComboRemoval(1234)}, 300000); //FIXED AS PER COMMENTS BELOW
setInterval will fire function ComboRemoval in 5 minutes, and it will remove ID 1234 from the box.
300000 = 5 minutes (1000 = 1 second, 60 x 5 = 300 seconds, 300 x 1000 = 300000)
Building upon #Gherkin's answer, using jQuery:
function addOption(key, text, timeout) {
var el = $("<option></option>")
.attr("value",key)
.text(text);
$('#test').append(el);
setTimeout(function() { el.remove(); }, timeout);
}
Now you can call:
addOption("value", "Text for option", 2000);
See it in action: http://jsfiddle.net/um9Cu/
You could expand addOption() to also lookup an existing item with the key and extend the timeout, or whatever you need to do.
You need to make use of a recursive function that calls setTimeout()
Example:
function myFunc() {
var minutes = 5;
//do stuff here
setTimeout(function() { myFunc() }, minutes*60000 };
}
When called myFunc() will fire and then call itself on a 5minute timer. The rest of the programs logic is 100% dependent on end-results.
I solved this problem by usign session. The newest data was written in session, so the new requests were according to the data in session. I used php and js in concert. Js was reading trough php session
Related
Problem is that setTimeout function within for loop is not getting the correct values despite the fact they were passed correctly. Second problem is that the sleep variable is not working, it simply ignores it. Other variables like i are acting strange, they are not going though the loop, they are going in a random order.
Inside function set_delay
console.log(i);
// 3,5,0,2,4,1 should be 0,1,2,3,4,5
console.log(sleep);
// 6000,6000,7000,9000,9000,10000, those ones are displayied in ASC order but shuold be randomly
console.log(share_screen_rate[i]);
//4,1,6,10,6,2,8 - this is not ok it's random
console.log(top);
// 749.5,2998,299.8,499.667,149,374.75 => this should be in order from smallest (149) to biggest (2998)
setTimeout(function() {
}, sleep);
if I change sleep to a numeric value like 2000 it is respected only for first iteration after nothing, it just goes at 0ms.
FULL CODE
https://jsfiddle.net/ojpv2nxu/
EXPECTED OUTPUT
This should be a simple script to scroll down the page and make pause based on the sleep variable and also read the page chunk by chunk based on the share_screen_rate variable
I think it is a logic issue.... You are expecting the setTimeout to happen x seconds after the last one. But they are firing x seconds after you set it. So it is working as expected.
If you want them to fire x seconds after the last, than you need to change the logic to keep track of the seconds and adjust the timers.
so top of the file add
var timeTrack = 0
and than you need to add to that value
timeTrack += sleep
setTimeout(function() {
}, timeTrack);
For one of my elements on my page, I want the text to change every ten seconds, and for the class to be changed. Text changing is easy, as is class changing, but I'm having trouble with my for loop, and I feel like I'm missing something.
I want to have the for loop choose a random faction in an array, and then apply that to the element. For my testing, I've been using console.log rather than DOM manipulation.
First, I set up my array:
var factions = ["Enforcers", "Reapers", "Ular Boys", "Roaches"];
Then, I want a variable that is a number chosen at random in reference to this array:
var x = factions[Math.floor(Math.random()*factions.length)];
From that, I want the ability to run the Math.floor and Math.random functions elsewhere.
function reDefine() {
x = factions[Math.floor(Math.random()*factions.length)];
console.log(x);
}
Finally, I want the for loop to run 200 times (I've chosen 200 times because it's far and beyond the time the user will be staying on the site), so I told it to count to 200 (i = 0; i < 200). After that, I wanted each time it iterated, to wait 10s, so I have a Timeout function with a delay of 10000 (milliseconds). Then, the code to reDefine and then, in the case of testing, console.log the new definition of the x variable.
function reChange() {
for (var i = 0; i < 200; i++) {
setTimeout(function() {
reDefine();
console.log("Chosen faction is now: " + x);
}, 10000);
}
}
Instead of counting to 1 (the first iteration), waiting 10000, and then redefining x, it redefines x two hundred times, then logs them all.
Is there something I'm specifically doing wrong here, perhaps with the Timeout function?
Is there something I'm specifically doing wrong here, perhaps with the Timeout function?
Yes! You're scheduling a bunch of deferred callbacks, but not actually waiting until one has finished to schedule the next.
You can fix that with something as simple as:
function reChange(currentIndex) {
setTimeout(function() {
reDefine();
console.log("Chosen faction is now: " + factions[currentIndex]);
// If we haven't gotten to the end of the list, queue up another one
var nextIndex = ++currentIndex;
if (nextIndex < factions.length) {
// Enqueue the next faction
reChange(nextIndex);
}
}, 10000);
}
Make sure to note that the function without the timeout has closure over the value of currentIndex for each call of reChange. That is, the next invocation does not replace currentIndex in any previous timeout, since primitives (including numbers) are passed by value. Closure in JS can be a tricky thing.
The core problem is that your execution right now looks like:
for each item
wait
log
rather than:
for the current item
wait
log
repeat
Because JS is single-threaded (for most intents and purposes), setTimeout adds a callback to be executed later. It doesn't block until the timeout has expired, like a traditional sleep would do.
Is there a way to store the current timestamp in a Javascript variable? The reason is I want to compare Javascript's current time value with a Django time variable, and whenever the time matches, it will send a popup notification.
I guess reloading the page maybe every 3 seconds or so would work, but that seems extremely inefficient.
I'm not sure exactly what you're trying to do here. It's not likely the times will ever match exactly unless you check every millisecond, but you can always check when the time is greater than the django variable, or within a certain range. This will check the time every three seconds.
var django = // Create a javascript date object from django timestamp here
var interval = setInterval(function(){checkTime()}, 3000);
function checkTime() {
var d = new Date();
if (d >= django) {
//Do something here
clearInterval(interval);
}
}
I'd like to use the setInterval function in jQuery in order to create an alert with the content of one array every 4 seconds. However my alerts show all the values of my array within a short amount of time and it stops for 4 seconds after having displayed all the values.
$.each(['html5', 'EDM', 'Coca Cola', 'creativity'], function(id,value) {
setInterval(function(){
alert(value);
}, 4000);
});
In this case, I'd like to display something like : Alert('html5') - 4 seconds - Alert('EDM') - 4 seconds - Alert('Coca Cola') - 4 seconds - Alert('creativity') - 4 seconds - Alert('html5') - 4 seconds - Alert('EDM') - 4 seconds - ...
Move the setInterval from the loop.
var arr = ['html5', 'EDM', 'Coca Cola', 'creativity'];
var index = 0;
setInterval(function() {
console.log(arr[index++ % arr.length]);
}, 4000);
Live DEMO
No jQuery needed.
Use a recursive setTimeout
var arr = ['html5', 'EDM', 'Coca Cola', 'creativity'];
var alertLoop = function(i) {
if (arr[i]) {
alert(arr[i]);
setTimeout(function(){alertLoop(i+1);}, 4000);
}
}
alertLoop(0);
Demo: http://jsfiddle.net/B5tJw/
Use of setInterval is discouraged. For an explanation, read here: http://bonsaiden.github.com/JavaScript-Garden/#other.timeouts
To summarise the problem:
setInterval fires the event at a regular interval, regardless of what else is happening on the page.
However, Javascript is not multi-threaded: it can only run one code sequence at a time. If setInterval is triggered while another code sequence is being run, the new code sequence will be blocked until the previous one is finished, and will wait for it.
If this happens repeatedly, you can end up with a large number of events waiting to be run.
You're using alert() to display your messages. alert() causes the code execution sequence to pause until the user responds to the message, but keeps it locked, so that other events cannot run their code. This is a particular problem for setInterval, because it fires new events at the specified time, regardless of whether something else is blocking the script.
The solution is to use setTimeout instead of setInterval.
setTimeout is only triggered once, but it is easy to tell it to trigger itself again inside its own function, so you can get the same effect as setInterval, but with much more control. Your code can wait until after the alert() has been accepted by the user before triggering the next event, which means that you won't get the problem of cascading events that can happen with setInterval.
Hope that helps explain things. The link I mentioned at the beginning is also very helpful.
I am building a real-time system which (with a use of websockets) updates a table with live data of different frequencies (can be 3 times per second, can be once every 2 seconds - dependant on the type of data).
I am currently struggling to find a way of letting the user know when a particular field has not been updated in the last 5 seconds. That is, if no new data is fetched, I shouldn't keep the old value there, but rather change it to '--' or something similar.
After a long way to the javascript, final function which updates fields looks like that (extremely simplified):
function changeValue(data){
var fieldId= data.fieldId;
var value = Math.round(data.value);
$('span#'+fieldId).text(value);
}
This function gets called each time a field needs to be changed. I've got between 2 and 40 different fields (dependant on the user) that are changed.
What is the best way of setting timers in order to change the values of the fields to '--' every 5 seconds, if no update has been made?
I would be really grateful for some tips,
Thanks,
Karol.
Since you want to indicate timeout on a per-field basis, you have two obvious options:
Have a global interval timer that ticks over fairly frequently and looks through all of your fields for a timeout.
Have independent timers for each field which just deal with that field.
I think on balance I prefer (1) to (2), because we're only dealing with one interval timer then and it makes the housekeeping simpler.
Since IDs in documents must be unique, we can use your field ID values as a key in a hash (an object) to store last updated times. This is kind of a spin on the previous answer but works on a per-field basis. So here's how we'd set those last updated times:
var lastUpdatedTimes = {};
function changeValue(data){
var fieldId= data.fieldId;
var value = Math.round(data.value);
$('span#'+fieldId).text(value);
lastUpdatedTimes[fieldId] = new Date().getTime();
}
Then you set up an interval timer to check each of them.
function checkFieldsForTimeout(){
var now = new Date.getTime();
// For each ID in lastUpdatedTimes, see if 'now minus
// last updated' is > 5000 and is so, set the field
// text to '--' and remove that entry from the last
// updated list with "delete lastUpdatedTimes[itemId]".
}
Should a timed-out field spring back to life, the "--" will be replaced by some real text again.
By deleting the last updated time from "lastUpdatedTimes" whenever we put "--" into a field, we make sure that the interval timer isn't wasting time processing fields that have already been timed out.
This answer was extended to handling multiple fields after the comment by #Andrew (please see also his answer).
Introduce a property updatedTime, which holds the last time the data was updated, in each data. A periodic timer checks updatedTime for all data and updates the text field if appropriate. The check has to be twice as often as the detection period. Your function changeValue() updates updatedTime and the text field.
function checkData() {
var now = new Date.getTime();
for "each data" {
if (now - data.updatedTime >= 5000) {
var fieldId = data.fieldId;
$('span#'+fieldId).text('--');
}
}
}
function changeValue(data) {
var fieldId = data.fieldId;
var value = Math.round(data.value);
$('span#'+fieldId).text(value);
data.updatedTime = new Date.getTime();
}
// Install periodic timer to check last updates:
setInterval(checkData, 5000 / 2); // interval = half the required detection period