The code below appends numbers in sequence from 1 to 10 when the start button is clicked. I'd like to use clearTimeout to cancel the operation when the stop button is clicked.
It seems to me that a dynamic variable must be created (where x is currently assigned the doSetTimeout function), but I have not yet found a way to do so. Any suggestions?
Thanks!
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
function doSetTimeout(func, func_param, time) {
setTimeout(function(){func(func_param);}, time);
}
function createNode(base) {
var node = document.createElement("p");
var writeI = base + "";
var textnode = document.createTextNode(writeI);
node.appendChild(textnode);
document.body.appendChild(node);
}
$(document).ready(function() {
$("#start").click(function() {
for (var i = 1; i <= 10; i++) {
var time = i*1000;
var x = doSetTimeout(createNode, i, time);
}
});
});
</script>
</head>
<body>
<button id="start">Start</button>
<button id="stop">Stop</button>
</body>
Get the return value of setTimeout, keep it in a list, and clear it when you click stop.
function doSetTimeout(func, func_param, time) {
return setTimeout(function(){func(func_param);}, time);
}
$(document).ready(function() {
var timeouts = [];
$("#start").click(function() {
for (var i = 1; i <= 10; i++) {
var time = i*1000;
timeouts.push(doSetTimeout(createNode, i, time));
}
});
$("#stop").click(function () {
for (var i = 0; i <= timeouts.length; i += 1) {
clearTimeout(timeouts[i]);
}
});
});
This might also clear timeouts that have already finished, but I doubt that's really very important.
Related
I've been wrestling with a timing issue in my code for a few nights now, and can't come up with the correct solution.
Psuedo code description:
//event listener on button trigger a die roll each time it is clicked
// call animation function
//generate random values x number of times
//display each result with setTimeout
//run code to determine final "settled upon" value and display results
HTML:
<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<head>
<title>Make Cards</title>
</head>
<body>
<p>Total:<span id="total"></span></p>
<div id="contain">
<div class="die"></div>
<div class="die"></div>
<div class="die"></div>
<div class="die"></div>
<div class="die"></div>
<div class="die"></div>
<br>
<button id="rollBtn">Roll</button>
<input type="number" value = "1" min="1" max="6" id = "numDice">
</div>
</body>
</html>
Javascript:
var diceValue = ["⚀", "⚁", "⚂", "⚃", "⚄",
"⚅"];
var dice = document.querySelectorAll(".die");
// select number of dice
var numDice = document.querySelector("#numDice");
// convert string to value
var newNumDice = Number(numDice.value);
var roll = document.querySelector("#rollBtn");
var total = document.querySelector("#total");
// make animation function
// call animation function
init();
function init(){
displayDice();
}
//THIS IS THE BUTTON LISTERNER
roll.addEventListener("click", function(){
//THIS SHOULD RUN BEFORE THE REST OF THE FUNCTION (BUT DOESN'T SEEM TO)
animate();
var subTotal = 0;
for (var i = 0; i < newNumDice; i++){
var value = generateRandomDice()
dice[i].innerHTML = diceValue[value];
subTotal = subTotal + (value+1);
total.innerHTML = subTotal;
}
for (var i = 0; i < 6; i++){
dice[i].style.color = "black";
}
})
numDice.addEventListener("click", function(){
total.innerHTML = "-";
newNumDice = Number(numDice.value);
resetDice();
displayDice();
// console.log(Number(numDice.value));
})
function resetDice(){
for (var i = 0; i < diceValue.length; i++){
dice[i].innerHTML = "";
}
}
// only display chosen number of dice
function displayDice(){
for (var i = 0; i < newNumDice; i++){
dice[i].innerHTML = diceValue[i];
}
}
function generateRandomDice(){
var dieSide = Math.floor(Math.random() * 6);
return dieSide;
}
//ATTEMPT AT WRITING CODE FOR ANIMATION
function animate(){
for (var i = 0; i < 50000; i++){
var ani = setTimeout(rolling, 650);
}
}
function rolling(){
for (var i = 0; i < newNumDice; i++){
var value = generateRandomDice()
dice[i].innerHTML = diceValue[value];
dice[i].style.color = "grey";
}
}
Not sure what is going on, but it appears to me that the animate(); code is not run until the rest of eventListener is finished. Any help is great, thank you.
The issue is that you are waiting for asynchronous code to finish before you execute synchronous code. Every time you call setTimeout, it is storing the function to call for when it's ready to be called (which is 650 ms from 'now'!).
To fix, you can await for your animation to finish. Here's how I got it working on your codepen:
Change animate to:
function animate() {
return new Promise((resolve, reject) => {
for (let i = 0; i < 50000; i++) {
setTimeout(() => {
rolling();
if(i == 49999)
resolve();
}, 650);
}
});
}
and then you can await for the Promise to resolve by changing your click listener to this:
roll.addEventListener("click", async function() {
await animate();
var subTotal = 0;
for (var i = 0; i < newNumDice; i++) {
var value = generateRandomDice();
dice[i].innerHTML = diceValue[value];
subTotal = subTotal + (value + 1);
total.innerHTML = subTotal;
}
for (var i = 0; i < 6; i++) {
dice[i].style.color = "black";
}
});
The result showing afterward was correct for me.
Hope that helps!
My code is the following. When I click the search button, it enters a for loop that prints 5000 times "hi". Before this calculation begins, I want to disable the button. After the console.log is finished, I want to reenable this button. But for some reason, this isn't working. (To be more precise, although here I am simply printing logs, my actually work involves various calculations that take around 5 seconds to finish using for loops.)
$("#search").click(function() {
$("#search").prop("disabled",true);
$("#search").text("Loading...");
var i;
for(i = 0; i < 50000; i++)
console.log("hi");
$("#search").prop("disabled",false);
$("#search").text("Finished...");
});
https://jsfiddle.net/gs793zhx/
Try using .delay() with duration set to 1 , .queue() , .promise() , $.Deferred()
$("#search").click(function() {
$(this).prop("disabled", true)
.text("Loading...")
.css("color", "red")
.delay(1, "p")
.queue("p", function(next) {
next()
})
.dequeue("p")
.promise("p")
.then(function() {
var elem = this;
return $.Deferred(function(d) {
var i = 0, max = 50000;
for (;i < max; i++) {
console.log("hi");
}
if (i === max) {
d.resolveWith(elem, [i])
}
}).promise()
}).then(function(data) {
console.log(this, data);
$(this).prop("disabled", false)
.css("color", "blue")
.text("Finished...");
})
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<button type="button" id="search" class="btn btn-primary" style="width:100px; height:30px;">SEARCH</button>
jsfiddle https://jsfiddle.net/gs793zhx/1/
use $("#search").attr("disabled","disabled"); and $("#search").removeAttr("disabled"); instead
Problem is with browser's performance to log hi for 50000 times.
You may put logs into js variable and dump the variable once into the console.
var btn = $("#search");
btn.click(function() {
btn.prop("disabled", true);
btn.text("Loading...");
var log = [];
for (var i = 0; 50000 > i; i++)
log.push("i: " + i);
console.log(log);
btn.prop("disabled", false);
btn.text("Finished...");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id='search'>Search</button>
$("#search").click(function() {
$("#search").prop("disabled",true);
$("#search").text("Loading...");
var i;
for(i = 0; i < 50000; i++) {
console.log("hi");
}
if(i==50000-1)
{
$("#search").prop("disabled",false);
$("#search").text("Finished...");
}
});
I am looping through a for loop to perform a simple calculation. The results of each iteration are stored into an array. The array has the correct number of elements but the output has exponentially too many elements.
HTML:
<script type="text/javascript" src="Fibonacci.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
(function($) {
$.fn.writeText = function(content) {
var contentArray = content,
current = 0,
elem = this;
setInterval(function() {
if(current < contentArray.length) {
elem.text(elem.text() + contentArray[current++]);
}
}, 1000);
};
})(jQuery);
</script>
</head>
<body>
<script>
document.write(getArray());
$(document).ready(function($){
var contentArray = getArray();
$('#calculations').writeText(contentArray);
});
</script>
<h3>Fibonacci Sequence:</h3>
<p id='calculations'></p>
External JS:
var result;
var x = 0;
var y = 1;
var resultArray = [x,y];
function FibonacciCalculation(){
for(var i = 2; i < 5; i++){
result = x + y;
x = y;
y = result;
resultArray.push(result);
}
}
function getArray(){
FibonacciCalculation();
return resultArray;
}
window.onload = function(){
FibonacciCalculation();
};
You need to reset your resultArray every time you run FibonacciCalculation function:
function FibonacciCalculation() {
resultArray = [x, y]
// ...
You called getArray two times the <script> part of the html so resultArray is called several time (2 and 4th line).
<script>
document.write(getArray());
$(document).ready(function($){
var contentArray = getArray();
$('#calculations').writeText(contentArray);
});
</script>
Also you should correct the < to > in your if condition because it seems that it will always be true.
if(current < contentArray.length) {
elem.text(elem.text() + contentArray[current++]);
}
the problem: after clicking a checkbox I change the cursor to "wait", but only after about 6 seconds the wait-cursor is to see. How to avoid this 6 sec pause ?
many thanks in advance
Wicki
code edited !
<html>
<head>
<title>Cursor-Test</title>
<script type="text/javascript">
var k = 0;
var t1 = 0;
var t2 = 0;
function cursor_wait() {
document.body.style.cursor = 'wait';
t1 = (new Date()).getTime();
k = k+1;
}
function cursor_clear() {
document.body.style.cursor = 'default';
}
function st() {
setTimeout(calc,500); //wait a bit
}
//long time action
function calc() {
ta = (new Date()).getTime();
var dummy = 0;
k = k+1;
for (var i=0; i<1000000;i++) {
for (var z=0; z<2000;z++) {
dummy = dummy + z + i;
}
}
tb = (new Date()).getTime();
tr = tb-ta;
cursor_clear();
t2 = (new Date()).getTime();
alert("nach clear, k="+k+" all time:"+(t2-t1)+" computing time:"+tr);
}
</script>
</head>
<body>
<h2>Cursor ändern: standard->wait->länger dauernde Aktion->standard</h2>
<div>wait-cursor erst nach ca. 6 sec</div>
<form name="some_form" action="index.php" method="get">
<input type="checkbox" name="nameless" value="5"
onMouseDown="cursor_wait()" onMouseUp="st()" /> Five
</form>
</body>
</html>
First off, setting c to the cursor style won't do you any good. Even if c were defined, it would be a string. Changing c's value would just make it point to a different string, not change the cursor's style. You may want to do this:
var c = document.body.style;
var t1 = 0;
var t2 = 0;
function cursor_wait() {
c.cursor = 'wait';
t1 = (new Date()).getTime();
k = k+1;
}
function cursor_clear() {
c.cursor = 'default';
}
//long time action
function calc() {
setTimeout(cursor_clear, 6000);
}
I removed other code to make it easier to see what you can do if you wanted to clear the cursor after 6 seconds and not block the UI.
I need to add append 10 div tags to another one but I need to wait random time before appending each one, something like this:
function start()
{
for (var i= 0; i< 10; i++)
{
var time = generateRandomWaitingTime();
sleep(time);
$('#div1').append('<div> div num' + i + '</div>');
}
}
I tried implementing my own sleep(time); function like here but it didn't work with me as it hangs any page event till the wait(time) finishes
setTimout() Seems to be exactly what you're looking for.
You should make use of setTimeout and a closure:
//closure
var addElement = function(i){
return function(){
$('#div1').append('<div> div num' + i + '</div>');
};
};
function start() {
for (var i = 0; i < 10; i++) {
var time = generateRandomWaitingTime();
setTimeout(addElement(i), time);
}
}
Living demo: http://jsfiddle.net/JaR34/
Update:
Living demo: http://jsfiddle.net/JaR34/1/
try this:
var elements = [1000,2000,3000,4000,5000,6000,7000];
function generateRandomWaitingTime(){
//will give you random index
var index = Math.floor((Math.random()*elements.length));
return (elements[index]);
}
function appendDiv(i){
var time = generateRandomWaitingTime();
setTimeout(function () {
$('#div1').append('<div> div num' + i + '</div>');
}, time);
}
for (var i = 0; i < 10; i++) {
appendDiv(i)
}
working fiddle here: http://jsfiddle.net/6neFA/1/