I want to return a value inside a setInterval. I just want to execute something with time interval and here's what I've tried:
function git(limit) {
var i = 0;
var git = setInterval(function () {
console.log(i);
if (i === limit - 1) {
clearInterval(git);
return 'done';
}
i++;
}, 800);
}
var x = git(5);
console.log(x);
And it's not working.
Is there any other way?
What I'm going to do with this is to do an animation for specific time interval. Then when i reached the limit (ex. 5x blink by $().fadeOut().fadeIn()), I want to return a value.
This is the application:
function func_a(limit) {
var i = 0;
var defer = $.Deferred();
var x = setInterval(function () {
$('#output').append('A Running Function ' + i + '<br />');
if (i == limit) {
$('#output').append('A Done Function A:' + i + '<br /><br />');
clearInterval(x);
defer.resolve('B');
}
i++;
}, 500);
return defer;
}
function func_b(limit) {
var c = 0;
var defer = $.Deferred();
var y = setInterval(function () {
$('#output').append('B Running Function ' + c + '<br />');
if (c == limit) {
$('#output').append('B Done Function B:' + c + '<br /><br />');
clearInterval(y);
defer.resolve('A');
}
c++;
}, 500);
return defer;
}
func_a(3).then( func_b(5) ).then( func_a(2) );
This is not functioning well, it should print A,A,A,Done A,B,B,B,B,B,Done B,A,A,Done A but here it is scrambled and seems the defer runs all function not one after the other but simultaneously. That's why I asked this question because I want to return return defer; inside my if...
if (i == limit) {
$('#output').append('A Done Function A:' + i + '<br /><br />');
clearInterval(x);
defer.resolve('B');
// planning to put return here instead below but this is not working
return defer;
}
Do you expect it to wait until the interval ends? That would be a real pain for the runtime, you would block the whole page. Lots of thing in JS are asynchronous these days so you have to use callback, promise or something like that:
function git(limit, callback) {
var i = 0;
var git = setInterval(function () {
console.log(i);
if (i === limit - 1) {
clearInterval(git);
callback('done');
}
i++;
}, 800);
}
git(5, function (x) {
console.log(x);
});
Using a promise it would look like this:
function git(limit, callback) {
var i = 0;
return new Promise(function (resolve) {
var git = setInterval(function () {
console.log(i);
if (i === limit - 1) {
clearInterval(git);
resolve('done');
}
i++;
}, 800);
});
}
git(5)
.then(function (x) {
console.log(x);
return new Promise(function (resolve) {
setTimeout(function () { resolve("hello"); }, 1000);
});
})
.then(function (y) {
console.log(y); // "hello" after 1000 milliseconds
});
Edit: Added pseudo-example for promise creation
Edit 2: Using two promises
Edit 3: Fix promise.resolve
Try to get a callback to your git function.
function git(limit,callback) {
var i = 0;
var git = setInterval(function () {
console.log(i);
if (i === limit - 1) {
clearInterval(git);
callback('done') // now call the callback function with 'done'
}
i++;
}, 800);
}
var x = git(5,console.log); // you passed the function you want to execute in second paramenter
Related
I want to call a second instance of the same function but with different values, after the first instance has completely finished, currently it calls both instances at the same time.
function printLetterByLetter(destination, message, speed) {
var i = 0;
var interval = setInterval(function () {
document.getElementById(destination).innerHTML += message.charAt(i);
i++;
if (i > message.length) {
clearInterval(interval);
}
}, speed);
}
printLetterByLetter("hc-a", "Hello world", 100);
printLetterByLetter("hc-b", "Hello world again.", 100);
How can I do this?
You can do using promise which wait for your first function execution then execute next otherwise you can use async/await which is also a good alternative.
Using Promise
function printLetterByLetter(destination, message, speed) {
var i = 0;
return new Promise(function(resolve, reject) {
var interval = setInterval(function() {
document.getElementById(destination).innerHTML += message.charAt(i);
i++;
if (i > message.length) {
clearInterval(interval);
resolve(true);
}
}, speed);
});
}
printLetterByLetter("hc-a", "Hello world", 100).then(function(resolve) {
printLetterByLetter("hc-b", "Hello world again.", 100);
}, function(reject) {});
Using async/await
function printLetterByLetter(destination, message, speed) {
var i = 0;
return new Promise(function(resolve, reject) {
var interval = setInterval(function() {
document.getElementById(destination).innerHTML += message.charAt(i);
i++;
if (i > message.length) {
clearInterval(interval);
resolve(true);
}
}, speed);
});
}
(async function() {
await printLetterByLetter("hc-a", "Hello world", 100);
printLetterByLetter("hc-b", "Hello world again.", 100);
})()
You can use Promises or async/await in order to do this. See the example below, that achieves your goal by utilizing Promises:
function printLetterByLetter(destination, message, speed) {
var i = 0;
// Return promise instance which you can use to execute code after promise resolves
return new Promise(function(resolve) {
var interval = setInterval(function() {
document.getElementById(destination).innerHTML += message.charAt(i);
i++;
if (i > message.length) {
clearInterval(interval);
// Resolve promise and execute the code in "then" block
resolve();
}
}, speed);
});
}
printLetterByLetter('hc-a', 'Hello world', 100).then(function() {
// This code gets executed when promise resolves
printLetterByLetter('hc-b', 'Hello world again.', 100);
});
<div id="hc-a"></div>
<div id="hc-b"></div>
You could use a classical approach with a stack and test the stack if the actual interval has ended.
var printLetterByLetter = function () {
function startInterval() {
var data = stack.shift(),
i = 0;
return data && setInterval(function () {
document.getElementById(data.destination).innerHTML += data.message[i++];
if (i >= data.message.length) {
clearInterval(interval);
interval = startInterval();
}
}, data.speed);
}
var stack = [],
interval;
return function (destination, message, speed) {
stack.push({ destination, message, speed });
interval = interval || startInterval();
};
}();
printLetterByLetter("hc-a", "Hello world", 100);
printLetterByLetter("hc-b", "Hello world again.", 50);
printLetterByLetter("hc-c", "See you later, alligator!", 200);
<div id="hc-a"></div>
<div id="hc-b"></div>
<div id="hc-c"></div>
I want to prevent my function from re-executing for one second after it's last executed. I've tried the method below, but it doesn't work.
function displayOut() {
// images
document.getElementById("imgBox").style.backgroundImage = "url(" + db.rooms[roomLoc].roomImg + ")";
// Diologue box
diologueBox.innerHTML = ""; // Clear Box
teleTyperDiologue(db.rooms[roomLoc].description +
" The room contains: " +
(function() {
let x = "";
for (let i = 0; i < db.items.length; i++) {
if (db.items[i].location === roomLoc && db.items[i].hidden === false) {
x += db.items[i].name + ", "
}
}
x = x.slice(0, x.length -2);
if (x === "") {
x = " nothing of special interest";
}
return x;
})()
+ ".");
pause();
};
function pause() {
setTimeout(function() {
// Wait one second!
}, 1000);
}
You could use a pattern like this:
var executing = false;
function myFunc() {
if(!executing) {
executing = true;
//Code
console.log('Executed!');
//End code
setTimeout(function() {
executing = false;
}, 1000);
}
}
setInterval(myFunc, 100);
So in your case, this would look like this:
var executing = false;
function displayOut() {
if(!executing) {
executing = true;
// images
document.getElementById("imgBox").style.backgroundImage = "url(" + db.rooms[roomLoc].roomImg + ")";
// Diologue box
diologueBox.innerHTML = ""; // Clear Box
teleTyperDiologue(db.rooms[roomLoc].description +
" The room contains: " +
(function() {
let x = "";
for (let i = 0; i < db.items.length; i++) {
if (db.items[i].location === roomLoc && db.items[i].hidden === false) {
x += db.items[i].name + ", "
}
}
x = x.slice(0, x.length -2);
if (x === "") {
x = " nothing of special interest";
}
return x;
})()
+ ".");
setTimeout(function() {
executing = false;
}, 1000);
}
};
Try to use throttle (http://underscorejs.org/#throttle) or debounce (http://underscorejs.org/#debounce) from underscore, one of those should fit your needs
This one will achieve that:
function run () {
console.log('Im running');
pause(1000);
};
function pause(s) {
console.log('Im paused');
setTimeout(() =>{
run();
}, s)
};
run();
The code above will run every 1 sec but if you want to make sure the function cant be runned again until you decide then you could use a flag instead like:
let canExecute = true;
function run () {
if (canExecute) {
console.log('Im running');
canExecute = false;
pause(1000);
}
};
function pause(s) {
console.log('Im paused');
setTimeout(() =>{
canExecute = true;
}, s)
};
run();
run();
run();
setTimeout(() =>{
run();
}, 2000)
This code will execute run function twice, first on time and then one more after 2 sec.
Say I have an array of functions that invoke a setTimeout.
[
function(cb){
setTimeout(function(){
cb('one');
}, 200);
},
function(cb){
setTimeout(function(){
cb('two');
}, 100);
}
]
Is there a way to access the time parameter (200, 100) and save the sum of that to a variable?
I want to execute a function only when both of those functions are done
A better approach is to use promises and Promise.all:
var task1 = new Promise(function(resolve,reject) {
setTimeout(function() {
//do something
resolve();
}, 100);
});
var task2 = new Promise(function(resolve,reject) {
setTimeout(function() {
//do something
resolve();
}, 200);
});
Promise.all([task1, task2]).then(function() {
//will be executed when both complete
});
You can mimic it with a closure for the count.
function out(s) {
var node = document.createElement('div');
node.innerHTML = s + '<br>';
document.getElementById('out').appendChild(node);
}
var f = [
function (cb) { setTimeout(function () { cb('one'); }, 100); },
function (cb) { setTimeout(function () { cb('two'); }, 200); }
],
useCounter = function () {
var count = 2;
return function (s) {
count--;
out(s + ' ' + count);
!count && out('done');
}
}();
f[0](useCounter);
f[1](useCounter);
<div id="out"></div>
I have this jQuery function that work. Every 2 lines is the same except a minor changes. How can I shorten it?
$(".c1").delay(5000).fadeOut("slow", function() {
$("#phone").addClass("c2").fadeIn("slow", function() {
$(".c2").delay(5000).fadeOut("slow", function() {
$("#phone").addClass("c3").fadeIn("slow", function() {
$(".c3").delay(5000).fadeOut("slow", function() {
$("#phone").addClass("c4").fadeIn("slow", function() {
$(".c4").delay(5000).fadeOut("slow", function() {
$("#phone").addClass("c5").fadeIn("slow", function() {
$(".c5").delay(5000).fadeOut("slow", function() {
$("#phone").addClass("c6").fadeIn("slow", function() {
$(".c6").delay(5000).fadeOut("slow", function() {
$("#phone").addClass("c7").fadeIn("slow", function() {
$(".c7").delay(5000).fadeOut("slow", function() {
$("#phone").addClass("c8").fadeIn("slow", function() {
$(".c8").delay(5000).fadeOut("slow", function() {
$("#phone").addClass("c9").fadeIn("slow", function() {
$(".c9").delay(5000).fadeOut("slow", function() {
$("#phone").addClass("c1").fadeIn("slow");
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
You could use a recursive function like this:
function phoneCall(i){
$(".c" + i).delay(5000).fadeOut("slow", function() {
$("#phone").addClass("c" + (i + 1)).fadeIn("slow", function() {
if(i <= 9) phoneCall(i + 1);
});
});
}
phoneCall(1);
It seems that the #phone element is the only one that ever gets the c_ class. If so, you can cache the element and eliminate a bunch of code.
var phone = $("#phone"), i = 0;
(function cycle() {
i = ((i % 9) + 1);
phone.addClass("c" + i).fadeIn("slow").delay(5000).fadeOut("slow", cycle);
})();
We can even get rid of a line of code by inlining the increment.
var phone = $("#phone"), i = 0;
(function cycle() {
phone.addClass("c" + ((++i % 9) + 1)).fadeIn("slow").delay(5000).fadeOut("slow", cycle);
})();
As #charlietfl noted, you may not want it to infinitely loop. If not, add a return statement.
var phone = $("#phone"), i = 0;
(function cycle() {
if (i === 9) return;
phone.addClass("c" + ((++i % 9) + 1)).fadeIn("slow").delay(5000).fadeOut("slow", cycle);
})();
And FWIW, numbering is usually a little simpler if you use 0 based indices.
var phone = $("#phone"), i = -1;
(function cycle() {
phone.addClass("c" + (++i % 9)).fadeIn("slow").delay(5000).fadeOut("slow", cycle);
})();
You can use something like that:
function inception(fromInt, tillInt){
if (fromInt < tillInt){
$('.c' + fromInt).delay(5000).fadeOut("slow",function(){
newInt = fromInt +1;
$('#phone').addClass('c'+newInt).fadeIn("slow", function() {
inception(newInt, tillInt));
}
});
}else{
if(fromint == tillInt){
$('.c' + fromInt).delay(5000).fadeOut("slow");
}
}
}
Then add to your code:
inception(1,9);
I don't know something like this?
var num = 2;
var HandlerForC = function () {
if (num < 10) {
$("#phone").addClass("c" + num).fadeIn("slow", HandlerForPhone);
} else {
$("#phone").addClass("c1").fadeIn("slow");
}
}
var HandlerForPhone = function () {
num++;
$(".c" + (num - 1)).delay(5000).fadeOut("slow", HandlerForC);
}
HandlerForPhone();
I've got this code and I don't know why all the functions in the loop are called at once!
this.line = function($l) {
var $this = this;
$this.$len = 0;
$('.active').hide(0,function(){
$this.$len = $l.length;
var j = 1;
$.each($l,function(i,item){
var t = setTimeout(function(){
$this._echoLine($l[i]);
clearTimeout(t);
if (j >= $this.$len) $('.active').show();
j++;
},500*j);
});
});
}
It's because you only increment j inside the timeout function, but the delay (which depends on j) is still 1 at the time the timeout handler is registered.
Seeing as you have a loop index variable anyway (i), try this:
$l.each(function(i, item) {
setTimeout(function() {
$this._echoLine($l[i]);
}, 500 * (i + 1));
});
// a separate timeout to fire after all the other ones
setTimeout(function() {
$('.active').show();
}, ($l.length + 1) * 500);
There's no need for the clearTimeout line, so no need to declare or store t either.
Hope it works.
this.line = function($l) {
var $this = this;
$this.$len = 0;
$('.active').hide(0,function(){
$this.$len = $l.length;
var j = 1;
$.each($l,function(i,item){
var t = setTimeout(function(){
$this._echoLine($l[i]);
clearTimeout(t);
if (j >= $this.$len) $('.active').show();
j++;
});
});
});
}
setTimeout(function() { this.line(); }, 500);