I'm creating a game where user writes a function that will execute and do stuff such as move a robot/rotate etc.
I've got this code :
function move(){
setTimeout(function(){
console.log("Log 1,5");
}, 3000);
return true;
}
function anotherMove(){
setTimeout(function(){
console.log("Log 2,5");
}, 2000);
return true;
}
function action(){
console.log("Log 1");
move();
console.log("Log 2");
anotherMove();
console.log("Log 3");
}
action();
Imagine move/anotherMove as robot movement and console.logs as calculations between those moves. Is there anyway to output logs correctly : 1 -> 1,5 -> 2 -> 2,5 (currently its 1 -> 2 -> 3 -> 1,5 -> 2,5) so basically that console.log waits for move/anotherMove to complete before executing these logs.
I can change move/anotherMove structure (it will be canvas animation) but I need action() structure stay as it is...
Thanks a lot !
Promises do just what you're looking for. These are available in ES6, or there are several libraries, for example, Q.
You'll start wrapping timeout in a promise...
function timeout(ms) {
return new Promise(function (resolve, reject) {
setTimeout(resolve, ms);
});
}
Now that timeout function will return a promise, which can be chained with another promise using the function then(). So, for example, your move() function can be improved as ...
function move(aString, aDelay) {
return timeout(aDelay).then( () => {
console.log(aString);
true;
});
}
The action function almost writes itself...
function action() {
console.log("Log 1");
return move("Log 1.5", 3000).then(() => {
console.log("Log 2");
move("Log 2.5", 2000);
}).then(() => {
console.log("Log 3");
});
}
Related
I am trying to call the function test() as many times as possible in a given time interval.
Here the function should be running for 15 seconds.
function test(): void; // Only type def
function run() {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 15000); // 15 seconds
while (true) {
test();
}
});
}
run()
.then(() => {
console.log('Ended');
});
However, the function doesn't stop running, and the Ended console.log does not appear. (Promise not resolved obviously). Is there a way to achieve this in Javascript ?
I was wondering, I could probably use console timers and put the condition in the while statement ? (But is that the best way ?)
The reason why your function does not stop executing is because resolving a promise does not stop script executing. What you want is to store a flag somewhere in your run() method, so that you can flip the flag once the promise is intended to be resolved.
See proof-of-concept below: I've shortened the period to 1.5s and added a dummy test() method just for illustration purpose:
let i = 0;
function test() {
console.log(`test: ${i++}`);
}
function run() {
return new Promise(resolve => {
let shouldInvoke = true;
setTimeout(() => {
shouldInvoke = false;
resolve();
}, 1500); // 15 seconds
const timer = setInterval(() => {
if (shouldInvoke)
test();
else
window.clearInterval(timer);
}, 0);
});
}
run()
.then(() => {
console.log('Ended');
});
I was following this tutorial and it was all making perfect sense until...
function first(){console.log('first')}
function second(){console.log('second')}
first()
second()
//first
//second
then:
function first(){
// Simulate a code delay
setTimeout( function(){
console.log(1);
}, 500 );
}
function second(){
console.log(2);
}
first();
second();
//2
//1
I get all that, but I don't understand how to then implement a callback so that it logs:
//1
//2
in that order.
I know it will be something like:
function first(cb){
// Simulate a code delay
setTimeout( function(){
console.log(1);
cb()
}, 500 );
}
but this blows up. can someone help me see how to use the callback correctly
It should be:
function first(cb){
setTimeout( function(){
console.log(1);
cb(); // <-- calling 'cb' is calling 'second'
}, 500 );
}
function second() {
console.log(2);
}
first(second); // pass 'second' as value of cb
UPDATE:
In case you want to use promises (as you mentionned in your comment), it should be:
function first() {
return new Promise(function(resolve) { // <-- Make the first function returning a promise.
setTimeout(function() {
console.log(1);
resolve();
}, 500);
});
}
function second() {
console.log(2);
}
first().then(function() { // <- 'first' returns a promise so you can .then on it
second();
});
I have 4-5 JavaScript functions which calls ajax and respond after sometime, but for example I am giving example of 3 functions without ajax code.
Here I want to ensure that func3 will call after two other functions func1 and func2.
func3();
func1();
func2();
function func1(){
setTimeout(function(){
console.log("func1");
}, 2000);
}
function func2(){
setTimeout(function(){
console.log("func2");
}, 3000);
}
function func3(){
setTimeout(function(){
console.log("func3");
}, 1000);
}
I want total time would be 4 seconds. func1 and func2 would run simultaneously in 3 seconds and then func3 in 1 second.
Call them at the end of the func before?
func3();
function func1(){
console.log("func1");
func2();
}
function func2(){
console.log("func2");
}
function func3(){
console.log("func3");
func1();
}
Edit 1:
func1();
function func1(){
setTimeout(function(){
console.log("func1");
func2();
}, 1500);
}
function func2(){
setTimeout(function(){
console.log("func2");
func3();
}, 1500);
}
function func3(){
setTimeout(function(){
console.log("func3");
}, 1000);
}
Just a quick primer on Promises:
A promise is an object that basically says, "This work isn't done yet, but I'll let you know when it is."
When you create a Promise, you can attach callback functions using .then(). When the promise is resolved - that is to say, it's work is finished - all of the callbacks will be executed. You can also attach callbacks with .fail() or something similar, and these will be executed if the Promise is rejected.
In your case, you might do something like:
func1().then(func2).then(func3);
function func1(){
var p = new Promise();
setTimeout(function(){
console.log("func1");
p.resolve();
}, 2000);
return p;
}
function func2(){
var p = new Promise();
setTimeout(function(){
console.log("func2");
p.resolve();
}, 3000);
return p;
}
function func3(){
var p = new Promise();
setTimeout(function(){
console.log("func3");
p.resolve();
}, 1000);
return p;
}
In addition, most Promise Libraries have a .whenAll() type function. This takes multiple Promises and calls its .then() callbacks when all promises have completed. So you could do:
whenAll(func1(), func2()).then(func3);
If you are in an environment where you can use EcmaScript6, there is a built in Promise library. Read this MDN article for information on that library.
Otherwise, I strongly recommend jQuery's promise library.
Note: The above code is just psuedocode. Read the documentation to see how to actually implement the Promises in those frameworks.
I made it as I want, like this. But I don't know its good of bad practice, I am not aware of promise and get some answer's but those were not working.
start = 0;
func1();
func2();
function func1(){
setTimeout(function(){
console.log("func1");
start++;
if(start==2){
func3();
}
}, 2000);
}
function func2(){
setTimeout(function(){
console.log("func2");
start++;
if(start==2){
func3();
}
}, 3000);
}
function func3(){
setTimeout(function(){
console.log("func3");
}, 1000);
}
Note : first function func1 prints in 2 seconds func2 in 1 second because 2 already gone, and then func3 in 1 second total 4 seconds cheers :)
let promises = [];
let ajaxCall = new Promise((resolve, reject) => {
console.log('ajaxCall');
setTimeout(() => {
resolve();
},1000);
});
let fn1 = new Promise((resolve, reject) => {
console.log('fn1');
ajaxCall.then(() => {
resolve();
});
});
let fn2 = new Promise((resolve, reject) => {
console.log('fn2');
ajaxCall.then(() => {
resolve();
});
});
promises.push(fn1);
promises.push(fn2);
Promise.all((promises)).then(() => {
console.log('fn3');
});
Hope this helps
I have a function that does some async work and returns a Promise, and I want to execute this function indefinitely until the promise is rejected.
Something like the following :
doSomethingAsync().
.then(doSomethingAsync)
.then(doSomethingAsync)
.then(doSomethingAsync)
// ... until rejection
I made a little CodePen so I can test potential solutions : http://codepen.io/JesmoDrazik/pen/pbAovZ?editors=0011
I found several potential answers but nothing seems to work for my case.
If anyone has a solution, I'd be glad, because I just can't find anything !
Thanks.
You can do
(function loop(){
doSomethingAsync().then(loop);
})();
But looking at your pen it's not clear where the rejection should come from. If you want to stop repeating an operation when the user clicks a button, you can change a state in the button handling and then do
(function loop(){
doSomethingAsync().then(function(){
if (!stopped) loop();
});
})();
Made a modification to your codepen
var FAKE_COUNT = 0;
function doSomething() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('doing something async: ' + FAKE_COUNT)
if (FAKE_COUNT < 10) {
resolve();
} else {
reject();
}
FAKE_COUNT ++;
}, 1000);
});
}
const button = document.querySelector('.js-button');
button.addEventListener('click', () => {
// maybe we can do something here ?
})
function test() {
doSomething().then(test).catch(() => {
console.log("Rejected")
});
}
test();
FAKE_COUNT just becomes the flag, so if you want to stop the promise with a click instead of a count you could just make it a bool and check that when executing the async task
Depending on where you want the logic and rejection to take place, but assuming you want the promise itself to be self executing (otherwise the asynchronous execution itself could loop) it could return itself as a new promise:
function doSomething() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('doing something async');
resolve();
}, 1000);
}).then(()=>doSomething());
}
For the rejection part, the easiest way would be to introduce a flag, (although that would make the promise a little less self containing):
var stop = false;
function doSomething() {
return new Promise((resolve, reject) => {
if(stop)
reject();
else{
setTimeout(() => {
console.log('doing something async');
resolve(); //(check for stop could be done here as well)
}, 1000);
}
}).then(()=>doSomething());
}
const button = document.querySelector('.js-button');
button.addEventListener('click', () => {
stop = true;
});
doSomething();
Using rsvp.js or any other promises/A+ implementation how can I turn code like...
console.log('step 1');
setTimeout(function() {
console.log('step 2');
setTimeout(function() {
console.log('step 3');
}, 100);
}, 300);
into a promises implementation?
Create a delay function which returns a Promise and it actually resolves it after the specified time elapses in setTimeout, like this
function delay(time) {
return new RSVP.Promise(function (resolve) {
setTimeout(resolve, time);
});
}
and then you can invoke it like this
console.log("step 1");
delay(3000)
.then(function () {
console.log("step 2");
return delay(1000);
})
.then(function () {
console.log("step 3");
});
Chain the promises:
// Set up the functions which contain the promises
function step1() {
return new RSVP.Promise(function(resolve, reject) {
resolve();
});
}
function step2() {
return new RSVP.Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, 300);
});
}
function step3() {
return new RSVP.Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, 100);
});
}
// Now execute them:
step1()
.then(step2)
.then(step3)
You can read more here: http://www.toptal.com/javascript/javascript-promises
If you're okay with using q, there's a very simple solution baked into the library:
console.log('step 1');
Q.delay(300).then(function() {
console.log('step 2');
return Q.delay(200);
}).then(function() {
console.log('step 3');
});
Follow the rules of thumb for promise development! First of all, we need to promisify the setTimeout calls, so that we get a function which returns us a promise for it. With the RSVP Promise constructor, it would look like this:
function delay(time) {
return new RSVP.Promise(function(resolve) {
setTimeout(resolve, time);
});
}
Now, we can chain the log statements using then instead of passing the callback right into setTimeout:
console.log("step 1");
delay(3000).then(function() {
console.log("step 2");
return delay(1000).then(function() {
console.log("step 3");
});
});
…and do get back a promise for when all three steps are executed.
However, the actual feature of then is that you can unnest the callbacks now, and get exactly the same result back. So your chain would look like this:
console.log("step 1");
delay(3000).then(function() {
console.log("step 2");
return delay(1000);
}).then(function() {
console.log("step 3");
});