I am using trying to have typing text in a div that has three different lines of text. So I want to call the function typed_text() for line one, then call it again for line two, then line three. I tried to use promises, but I was lost when it came to using setTimeout() and recursion.
I call the function something like this.
typed_text("#line_one", frame.text_one, 0, 25)
typed_text("#line_two", frame.text_two, 0, 25)
typed_text("#line_three", frame.text_three, 0, 25)
function typed_text(div, text, index, interval)
{
if (quit_typed_text == true) {
interval = 0;
}
if (index < text.length) {
$(div).append(text[index++]);
setTimeout(function() {typed_text(div, text, index, interval); }, interval);
} else {
click_disabled = false;
}
}
Edit: Here is what I was attempting using recursion and promises
typed_text("#text_one", frame.text_one, 0, 25).then(typed_text("#text_two", frame.text_two, 0, 25));
function typed_text(div, text, index, interval)
{
return new Promise(function (resolve) {
if (quit_typed_text == true) {
interval = 0;
}
if (index >= text.length) {
click_disabled = false;
resolve();
}
}).then(function() {
if (index < text.length) {
$(div).append(text[index++]);
/* Problem is here, setTimeout.then() does not exist as a function */
setTimeout(function() {typed_text(div, text, index, interval); }, interval);
}
});
}
using promises, your typed_text function can be rewritten as follows
function typed_text(div, text, index, interval) {
return new Promise(function(resolve) {
var doit = function() {
if (quit_typed_text == true) {
interval = 0;
}
if (index < text.length) {
$(div).append(text[index++]);
setTimeout(doit, interval);
} else {
click_disabled = false; // not sure this should be here
resolve();
}
};
doit(); // oops forgot this line
});
}
Then, to use it, simply use promise chaining as follows:
typed_text("#line_one", frame.text_one, 0, 25).then(function() {
return typed_text("#line_two", frame.text_two, 0, 25);
}).then(function() {
return typed_text("#line_three", frame.text_three, 0, 25);
}).then(function() {
// all done here - perhaps this is where click_disabled = false should be?
});
It seems there's no asynchronous function in your code, so why don't you call your function "typed_text" in a setTimeOut ?
By example :
setTimeout(function() { typed_text("#line_one", frame.text_one, 0); }, 25);
setTimeout(function() { typed_text("#line_two", frame.text_two, 0); }, 50);
setTimeout(function() { typed_text("#line_three", frame.text_three, 0); }, 75);
function typed_text(div, text, index){
if (quit_typed_text == true) interval = 0;
if (index < text.length) $(div).append(text[index++]);
else click_disabled = false;
}
Could this be ok for you ?
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 have a piece of code:
var a = false;
function wait(milliseconds, async) {
if(!async) {
setTimeout(function() {
console.log('Sync timer done.');
a = true;
return true;
}, milliseconds*1000);
}
(...)
f_recipe.forEach(function(item, index) {
if (obj['actual_step'] != 0 && obj['actual_step'] != index ) {
e = "Desync";
throw e;
};
console.log("Step: " + obj.actual_step);
if(item.substr(item.length - 6) != "false)"){
if (eval(item)) {
obj['actual_step']++;
}
} else {
eval(item);
var ival = setInterval(function(){
if(a) {
console.log('do the next thing');
clearInterval(ival);
}
}, 1000);
}
});
But when I get to 'do the next thing'(interval complete), the forEach loop doesn't continue to the next element of the array. 'a' is set to true after timeout (kind of a synchronous wait in JS). f_recipes is a string array with function call (e.g. 'wait(20, false)').
How to get it to work?
What you're trying to do seems like a very bad idea, but promises can help with this (using Bluebird here because it provides Promise.delay and Promise.each):
function wait(seconds, dontActuallyWait) {
return dontActuallyWait ? null : Promise.delay(seconds * 1000);
}
function runSequence(things) {
return Promise.each(things, function(thing) {
return eval(thing);
});
}
runSequence([
'console.log("hello")',
'wait(2, false)',
'console.log("hello again")',
'wait(5, false)',
'console.log("goodbye")'
]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.5.1/bluebird.min.js"></script>
I'm a PHP developer and I want to make FlipClock's inital value ease-in. I think it can be done by:
Making clock.incerement()'s interval value flexible, Based on how close is current value, to initial value.
Make a break when the current value was equal to initial value.
I changed this code:
var clock;
var initial = 5000;
$(document).ready(function() {
clock = new FlipClock($('.clock'), 0, {
clockFace: 'Counter',
});
setTimeout(function() {
setInterval(function() {
if(clock.getTime().time >= initial) {
clock.stop();
} else {
clock.increment();
}
}, 100);
});
});
to this one:
var clock;
var initial = 5000;
$(document).ready(function() {
clock = new FlipClock($('.clock'), 0, {
clockFace: 'Counter',
});
setTimeout(function() {
setInterval(function() {
if(clock.getTime().time >= initial) {
clock.stop();
} else {
clock.increment();
}
}, function() {
if ((initial - clock.getTime().time) > 1000) {
return 1;
} else if ((initial - clock.getTime().time) > 100) {
return 10;
} else {
return 1000;
}
});
});
});
But did not worked. What i have to do?!
Thank you.
The interval value is supposed to a time in milliseconds, not a function.
One other way to do it is that you calculate the timeout value is as such
setTimeout(function(){
var x = CalculateCurrentInterval(clock);
setInterval(function() {
if(clock.getTime().time >= initial) {
clock.stop();
} else {
clock.increment();
}
}, x);
})
var CalculateCurrentInverval = function(clock) {
if ((initial - clock.getTime().time) > 1000) {
return 1;
} else if ((initial - clock.getTime().time) > 100) {
return 10;
} else {
return 1000;
}
}
I have not tried it but it should work.
Problem is that you are sending in a function where a number is expected
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
I've used this
http://jsfiddle.net/3KydB/
and tried to modify it for 3 divs:
window.switchIn = function () {
$('.chart_1').fadeToggle(function() {
$('.chart_2').fadeToggle(function() {
$('.chart_3').fadeToggle(function() {
setTimeout(function() {window.switchOut();}, 6000);
});
});
});
}
window.switchOut = function () {
$('.chart_3').fadeToggle(function() {
$('.chart_2').fadeToggle(function() {
$('.chart_1').fadeToggle(function() {
setTimeout(function() {window.switchIn();}, 6000);
});
});
});
}
setTimeout(function() {window.switchIn();}, 6000)
The first one fades in and out fine, then the second one fades in with the third one below it, then back to the first one etc.
I think you would want something like the following: http://jsfiddle.net/mEeAt/
window.switch1 = function () {
$('.chart_3').fadeToggle(function() {
$('.chart_1').fadeToggle(function() {
setTimeout(window.switch2, 6000);
});
});
}
window.switch2 = function () {
$('.chart_1').fadeToggle(function() {
$('.chart_2').fadeToggle(function() {
setTimeout(window.switch3, 6000);
});
});
}
window.switch3 = function () {
$('.chart_2').fadeToggle(function() {
$('.chart_3').fadeToggle(function() {
setTimeout(window.switch1, 6000);
});
});
}
setTimeout(window.switch2, 6000)
So each function is responsible for fading out the active element, fading in the next element, and setting a timeout for the next function in the cycle.
Of course there is a lot of repeated code here, so you would probably be better off creating a function to make this more generic: http://jsfiddle.net/mEeAt/1/
function cycle(delay) {
var elements = Array.prototype.slice.call(arguments, 1);
var functions = [];
for (var i = 0; i < elements.length; i++) {
functions.push(function (i) {
var prev = i === 0 ? elements.length - 1 : i - 1;
var next = (i + 1) % elements.length;
return function() {
elements[prev].fadeToggle(function() {
elements[i].fadeToggle(function() {
setTimeout(functions[next], delay);
});
});
};
}(i));
}
functions[1](); // start cycle by fading in the second element
}
cycle(6000, $('.chart_1'), $('.chart_2'), $('.chart_3'));