Javascript Loop with Sleep - javascript

I have a gridview and a dropdownlist in my ASP in the C# i have functionality that will allow the user to select which dropdownlist item will apply to each gridview row.
so in the JavaScript i want slideshow like functionality for each dropdownlist item and count how many gridview rows contain that item.
I'm attempting to get the code to run at a consistent speed (2 seconds per dropdownlist item)
Below is my JavaScript
$(document).ready(function () {
loop();
});
function loop() {
var ddl = document.getElementById("cphMain_ddlInc");
for (var j = 1; j < ddl.options.length; j++) {
setTimeout(shippedEmbryos(j), 2000);
}
}
function shippedEmbryos(j) {
var st = $("input[id*=txtShipped]");
var grid = document.getElementById("cphMain_gvFertEntry");
var ddl = document.getElementById("cphMain_ddlInc");
var embryos = 0;
var ddlValue = ddl.options[j].innerHTML;
for (var i = 1; i < grid.rows.length - 1; i++) {
if (ddlValue == grid.rows[i].cells[2].innerHTML) {
var txtbox = $("input[id*=txtShipped]");
var x = txtbox[i].value;
if (x == "") {
x = 0;
}
}
else {
x = 0;
}
embryos += parseInt(x);
}
var label = document.getElementById("cphMain_lblShippedEmbryos");
label.innerHTML = "Embryos Shipped for " + ddlValue + ": " + embryos;
};

JavaScript doesn't work like that ...
The language is single-threaded, which means that if you sleep for two seconds everything is locked up while you do. That includes your current window -- everything you are trying to draw on screen.
In many browsers all windows freeze.
You need to do event-driven programming here where you fire off an event to draw the next lie.
There are a number of work-arounds depending on if you can use ES7 await/async through a cross compiler or if you can use ES6's Promises. Lastly ES5 gives you setTimeout
What is the JavaScript version of sleep()?

If you want to wait some time in JS, you can't keep looping because it would block thread.
You could use setTimeout method instead or you can use Window.requestAnimationFrame() method, it would fit in your current code better.
Here is draft(modified from MDN sample code)
var start;
function step(timestamp) {
var progress;
if (start === null) start = timestamp;
progress = timestamp - start;
// trigger every 2000ms, equal 2s
if (progress >= 2000) {
//reset start time
start = timestamp;
// do whatever you want ..., such as call shippedEmbryos()
//start another loop
requestAnimationFrame(step);
}
}
MDN:Window.requestAnimationFrame()- This method call every frame and it is browser friendly API(would not affect page rendering performance).
It has one argument : timestamp, browser system would pass current timestamp in automatically.
look like this: 55378.47799999872 55395.189000002574 55411.900000006426....
Then you can keep call the method like recursive.
If you want to stop, just simply not call the method.

Related

Can't find the way to proper timeout or interval

I can't find the way to timeout or pause (tried for and counting to big numbers) click event. I use alert('x') to stop before $(arr[i-1]).click(); and then I have to press enter after that. But I want to automically pause after click event for about 300 ms.
javascript:
var arr = $("a.farm_icon_b");
var x = document.getElementById("plunder_list").rows;
var images;
for (var i = 0; i < x.length; i++) {
var z = x[i].id;
if (!!z) {
images = document.getElementById(String(z)).getElementsByTagName('img');
for (var j = 0; j < images.length; j++) {
if (!!images) {
if (images[j].src == "https://dspl.innogamescdn.com/8.116/36249/graphic/command/attack.png") {
if (images[j].tooltipText == "1 atak w drodze") {
alert('x');
$(arr[i - 1]).click();
} else if (images[j].tooltipText == "2 ataki w drodze") {
alert('y');
$(arr[i - 1]).click();
}
}
}
}
}
}
You can use javascript setTimeout function to hold or stop your script to execute for time as per your requirement. check this Link for more details. All the best.
setTimeout(function(){
$(arr[i - 1]).click();
}, 3000); // 3000 is stands for 3 second you can change it according to your requirementcode here
Important Note (thanks to #Thomas for highlighting this) This function doesn't "sleep" for 300ms, it freezes the page. The browser simply is stuck in that loop for 300ms and can't do anything untill this is over.
I think this is the function you are looking for. It will help you put a 300ms delay before the button clicks.
function pausecomp(millis)
{
var date = new Date();
var curDate = null;
do { curDate = new Date(); }
while(curDate-date < millis);
}
Source: http://userscripts-mirror.org/scripts/review/408779
Usage:
pausecomp(300); // Sleep for 300ms
$(arr[i - 1]).click();
Disclaimer:
Ideally, a setTimeout() based solution is the best approach for such problems in Javascript (as suggested by Akansh). However, a linear for-loop based approach will most likely not work for such a solution, and you will need to devise a callback functions based solution that relies on deferred execution.

Setting Child CascadingDropDown Asynchronously in Javascript

I have 3 CascadingDropDowns and am trying to set their values from the clientside. I have a solution that works, but uses setTimeout which is not always reliable, so I am looking for a more stable solution.
The problem I'm having is that after setting the Parent CascadingDropDown, its child is not immediately populated -- it takes some milliseconds to load the data. Therefore in the javascript code if I assign the parent dropdown a value and then try to loop through the corresponding child values to find the value I want, the child dropdown will not be immediately populated since its data has not come back from the web service.
Here is the code using timeouts that is working for me -- but I want to get away from the timeouts.
for (i = 0; i < ddlPC1.length; i++) {
if (ddlPC1.options[i].value == test1) {
var ajaxcdd_ddlPC2 = $find(document.getElementById('ajaxcdd_ddlPC2ID').value);
ddlPC1.selectedIndex = i;
ajaxcdd_ddlPC2._onParentChange(null, false);
break;
}
}
setTimeout(function () {
var ddlPC2 = document.getElementById(document.getElementById('ddlPC2ID').value);
for (i = 0; i < ddlPC2.length; i++) {
if (ddlPC2.options[i].value == test2) {
ddlPC2.selectedIndex = i;
var ajaxcdd_ddlPC3 = $find(document.getElementById('ajaxcdd_ddlPC3ID').value);
ajaxcdd_ddlPC3._onParentChange(null, false);
break;
}
}
setTimeout(function () {
var ddlPC3 = document.getElementById(document.getElementById('ddlPC3ID').value);
for (i = 0; i < ddlPC3.length; i++) {
if (ddlPC3.options[i].value == test3) {
ddlPC3.selectedIndex = i;
break;
}
}
}, 250);
}, 250);
test1, test2, and test3 are the values that I want to assign the dropdowns to. If I remove the timeouts, the for loops will not iterate since there is not any data immediately populated in the child drop downs (data coming from webservice, and takes about 100 ms).
Is there a way to set the child drop downs (ddlPC2, ddlPC3) without having to use setTimeout?
Thank you.

CSS3 animationStarted event trigger with a delay of 25/30 milliseconds

i have made a JSFiddle to show the problem
http://jsfiddle.net/molokoloco/yvTje/
In few words, i put some listener on the animationStart event, add a new class to the element and then, in a plugin i do, i need to check if the element have an animation (can be associated with the class) before doing, or not, something.
My probleme is i have to wait 25/80 millisecond before it's possible to check if an animation is started or not...
Something i do bad or any suggestion ?
var animationStarted = false,
s = '';
var listener = function(e) {
switch (e.type) {
case "animationstart":
case "webkitAnimationStart":
// BUT "animationstart" do not trigger instantaneously
// For the moment i compute 25 milliseconds on my Chrome & FF
var diff = (new Date().getTime()) - s;
console.log('animationStarted after ' + diff + ' ms'); // HERE THE RESULT : 30ms
break;
}
};
var setup = function() {
var e = document.getElementById("watchme");
e.addEventListener("animationstart", listener, false);
e.addEventListener("webkitAnimationStart", listener, false);
// HERE WE ADD THE CLASS
e.className = "slidein";
s = new Date().getTime(); // Time at witch the class (with anim) is applyed
};
setup();
Use feature detection even before you try to start the animation.
var div = document.createElement("DIV");
div.style["animation"] = "animName 5s infinite";
div.style["WebkitAnimation"] = "animName 5s infinite";
if (div.style["animationDuration"] == "5s") {
// Supports animation
} else (div.style["WebkitAnimationDuration"] == "5s") {
// Supports -webkit-animation
}
This tests for the browser's ability to set individual style attributes using shorthand. If you just set a value and read it back the same way, you'll get false positives.
EDIT: Sorry, misunderstood the problem.
Regarding using events to check for stuff, you will probably have to wait a few milliseconds, no matter what you do... You could check the style definitions themselves using document.styleSheets, but that would be pretty exhausting, depending on the specificity of the css.
var animationName = "";
for (var i = 0; i < document.styleSheets.length; ++i) {
var sheet = document.styleSheets[i];
var rules = sheet.cssRules || sheet.rules;
for (var j = 0; j < rules.length; ++j) {
var rule = rules[j];
if (theElement.matchesSelector(rule.selectorText)) {
var theStyle = rule.style;
animationName = theStyle["WebkitAnimationName"];
}
}
}
It's a pretty crude way of doing this, I know...

How to stop all timeouts and intervals using javascript? [duplicate]

This question already has answers here:
javascript: Clear all timeouts?
(13 answers)
Closed 6 years ago.
I'm working on an ajax web appliation which contains many running timeouts and intervals. And now I need to clear all running timeouts and intervals sometimes. Is there a simple way to stop everything without need to store every timeout and interval ID and iterate through them and clear them?
Sometimes it's possible to save the timer Id / Handle to clear it later which would be the best solution. So this is a second best. But I wanted to give a better understanding of what's going on. It basically grabs the highest timer id and clears everything less than that. But it's also possible to clear other timers that you do not want to clear!
It is a little hackish, so be warned!
// Set a fake timeout to get the highest timeout id
var highestTimeoutId = setTimeout(";");
for (var i = 0 ; i < highestTimeoutId ; i++) {
clearTimeout(i);
}
Updated answer after reading the duplicate I closed this question with -
It works and tested in Chrome on OSX
// run something
var id1 = setInterval(function() { console.log("interval", new Date())}, 1000);
var id2 = setTimeout(function() { console.log("timeout 1", new Date())}, 2000);
var id3 = setTimeout(function() { console.log("timeout 2", new Date())}, 5000); // not run
setTimeout(function() { console.log("timeout 3", new Date())}, 6000); // not run
// this will kill all intervals and timeouts too in 3 seconds.
// Change 3000 to anything larger than 10
var killId = setTimeout(function() {
for (var i = killId; i > 0; i--) clearInterval(i)
}, 3000);
console.log(id1, id2, id3, killId); // the IDs set by the function I used
NOTE: Looked at window objects that had a typeof number - funnily enough IE assigns an 8 digit number, FF a single digit starting with 2
Here is a workaround.
window.timeoutList = new Array();
window.intervalList = new Array();
window.oldSetTimeout = window.setTimeout;
window.oldSetInterval = window.setInterval;
window.oldClearTimeout = window.clearTimeout;
window.oldClearInterval = window.clearInterval;
window.setTimeout = function(code, delay) {
var retval = window.oldSetTimeout(code, delay);
window.timeoutList.push(retval);
return retval;
};
window.clearTimeout = function(id) {
var ind = window.timeoutList.indexOf(id);
if(ind >= 0) {
window.timeoutList.splice(ind, 1);
}
var retval = window.oldClearTimeout(id);
return retval;
};
window.setInterval = function(code, delay) {
var retval = window.oldSetInterval(code, delay);
window.intervalList.push(retval);
return retval;
};
window.clearInterval = function(id) {
var ind = window.intervalList.indexOf(id);
if(ind >= 0) {
window.intervalList.splice(ind, 1);
}
var retval = window.oldClearInterval(id);
return retval;
};
window.clearAllTimeouts = function() {
for(var i in window.timeoutList) {
window.oldClearTimeout(window.timeoutList[i]);
}
window.timeoutList = new Array();
};
window.clearAllIntervals = function() {
for(var i in window.intervalList) {
window.oldClearInterval(window.intervalList[i]);
}
window.intervalList = new Array();
};
It works for set/clear timeout/interval functions called after these lines are executed. Try and see it works:
setInterval('console.log(\'a\')', 1000);
setInterval('console.log(\'b\')', 500);
setInterval('console.log(\'c\')', 750);
setTimeout('clearAllIntervals()', 10000);
Proxying does the magic.
var noofTimeOuts = setTimeout('');
for (var i = 0 ; i < noofTimeOuts ; i++) clearTimeout(i);
var max = setTimeout(function(){ /* Empty function */ },1);
for (var i = 1; i <= max ; i++) {
window.clearInterval(i);
window.clearTimeout(i);
if(window.mozCancelAnimationFrame)window.mozCancelAnimationFrame(i); // Firefox
}
There's nothing built-in, but it's pretty easy to blast through all currently outstanding deferred execution functions by calling this clearAll() function:
function clearAll() {
for (var i = setTimeout(function() {}, 0); i > 0; i--) {
window.clearInterval(i);
window.clearTimeout(i);
if (window.cancelAnimationFrame) window.cancelAnimationFrame(i);
}
}
If you are in charge of the page you run, and can wrap the native deferred execution functions in wrappers that do the house keeping for of course equip each setter function with a corresponding .clearAll() too:
(function(deferFunctions) {
for (var setter in deferFunctions) (function(setter, clearer) {
var ids = [];
var startFn = window[setter];
var clearFn = window[clearer];
function clear(id) {
var index = ids.indexOf(id);
if (index !== -1) ids.splice(index, 1);
return clearFn.apply(window, arguments);
}
function set() {
var id = startFn.apply(window, arguments);
ids.push(id);
return id;
}
set.clearAll = function() { ids.slice(0).forEach(clear); };
if (startFn && clearFn) {
window[setter] = set;
window[clearer] = clear;
}
})(setter, deferFunctions[setter]);
})(
{ setTimeout: 'clearTimeout'
, setInterval: 'clearInterval'
, requestAnimationFrame: 'cancelAnimationFrame'
});
To try that it works, you could then try doing this, for instance, which will remain silent, as none of the callbacks end up firing before they're cancelled again:
// Some example timers of all types:
requestAnimationFrame(console.error);
setInterval(console.info, 1000, 'interval');
setTimeout(alert, 0, 'timeout');
// Now you can clear all deferred functions
// by execution type, whenever you want to:
window.setTimeout.clearAll();
window.setInterval.clearAll();
window.requestAnimationFrame.clearAll();
A little hack added to Gokhan Ozturk's answer
If you are using third party libraries which uses Timeouts and Intervals then they will also be cleared, so I added one parameter to notify function that this interval is to be push'ed or not to array.
window.setTimeout = function(code, delay, toBeAdded) {
var retval = window.oldSetTimeout(code, delay);
var toBeAdded = toBeAdded || false;
if(toBeAdded) {
window.timeoutList.push(retval);
}
return retval;
};
... // likewise for all functions.
You might be better off creating a scheduler. Take a look at this approach by Nader Zeid:
https://www.onsip.com/blog/avoiding-javascript-settimeout-and-setinterval-problems
It's an approach that help create some determinacy (because "the time interval argument of each of those functions really only establishes that the given function will execute after at least that amount of time. So a timed event can miss its target by literally any amount of time.").
Specifically, to the question you raise here, you can easily add and remove functions from the queue. While this response is long after the question was raised, hopefully it's helpful to any who find themselves struggling with Timeouts and Intervals.
You cannot clear any timeouts and intervals you don't know about.
You'd need something like getTimeoutList which isn't in the DOM3 spec, or even planned, AFAIK.
The previous proxying trick is nice, but if you have a lot of timeouts and intervals, I would not fill the arrays with consecutive numbers [1,2,3....], but with intervals. For example, instead of having [1,2,3,7,8,9], you would have maybe something like ['1-3','7-9'] or [[1,3],[7,9]], as a memory optimization. Of course this trick is only suited if you have a lot of timeouts and intervals and also if you would not stop arbitrary intervals that often.

How to use setTimeout / .delay() to wait for typing between characters

I am creating a simple listbox filter that takes the user input and returns the matching results in a listbox via javascript/jquery (roughly 5000+ items in listbox). Here is the code snippet:
var Listbox1 = $('#Listbox1');
var commands = document.getElementById('DatabaseCommandsHidden'); //using js for speed
$('#CommandsFilter').bind('keyup', function() {
Listbox1.children().remove();
for (var i = 0; i < commands.options.length; i++) {
if (commands.options[i].text.toLowerCase().match($(this).val().toLowerCase())) {
Listbox1.append($('<option></option>').val(i).html(commands.options[i].text));
}
}
});
This works pretty well, but slows down somewhat when the 1st/2nd char's are being typed since there are so many items.
I thought a solution I could use would be to add a delay to the textbox that prevents the 'keyup' event from being called until the user stops typing. The problem is, I'm not sure how to do that, or if its even a good idea or not.
Any suggestions/help is greatly appreciated.
You can do a delay like this:
$('#CommandsFilter').keyup(function() {
clearTimeout($.data(this, 'timer'));
var wait = setTimeout(search, 500);
$(this).data('timer', wait);
});
function search() {
var temp = $("<select />");
for (var i = 0; i < commands.options.length; i++) {
if (commands.options[i].text.toLowerCase().match($(this).val().toLowerCase())) {
$('<option></option>', { val: i, html: commands.options[i].text }).appendTo(temp);
}
}
Listbox1.empty().append(temp.children());
}
This stores a timeout on the element you're typing in, if 500ms (adjust as needed) passes between keystrokes, a search executes. Also this appends the elements in a document fragment then into the DOM (still preserving encoding, etc). Depending on the number of items, this may be a decent performance boost as well.
If the commands drop-down isn't changing, I'd suggest the following (note I've dropped jQuery for better performance and compatibility). There are several improvements:
Timer to delay updating the filtered list once half a second has elapsed since the last keypress
List of command texts is pre-cached
Unnecessary use of match replaced with indexOf
Uses fast native DOM manipulation that works in all scriptable browsers since the 1990s
A quick test suggests that for a drop-down with 5000 options containing short strings, it's between 10 and 30 times faster than the jQuery equivalent in most browsers.
Code:
var commands = document.getElementById("DatabaseCommandsHidden");
var filteredDropDown = document.getElementById("Listbox1");
var filterInput = document.getElementById("CommandsFilter");
var timer;
// Create a cached list of the lower case text of the commands drop-down
var commandTexts = [], commandText;
for (var i = 0, len = commands.options.length; i < len; ++i) {
commandText = commands.options[i].text;
commandTexts.push({original: commandText, lower: commandText.toLowerCase()});
}
function populateFilteredDropDown() {
timer = null;
var val = filterInput.value.toLowerCase(), commandText;
var opts = filteredDropDown.options;
filteredDropDown.length = 0;
for (var i = 0, len = commandTexts.length; i < len; ++i) {
commandText = commandTexts[i];
if (commandText.lower.indexOf(val) > -1) {
opts[opts.length] = new Option(commandText.original);
}
}
}
filterInput.onkeyup = function() {
if (timer) {
window.clearTimeout(timer);
}
timer = window.setTimeout(populateFilteredDropDown, 500);
};

Categories

Resources