make setTimeout as generic function and exec timeout - javascript

I have 3 functions, assume they are function a, b and c. All of them require a delay to start in different scope.
I can do in different places and event like this
setTimeout(function()a()},100);
setTimeout(function()b()},100);
setTimeout(function()c()},100);
but how can I make it cleaner?

This is exactly what ES6 Promises were made for.
function a() { console.log('a') }
function b() { console.log('b') }
function c() { console.log('c') }
function foo() {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve();
}, 100);
});
}
foo()
.then(a)
.then(b)
.then(c)
I understand this example is a little vague. But if you understand promises you can adapt it pretty well to your problem (and if you are not familiar with promises you can master Promises in a matter of hours).
You could also use Observables from Rjrx. The "fromInterval" operator is what you are looking for. Observables might be part of ES7.

You can try this approach.
function a() {
console.log("function a");
}
function b() {
console.log("function b");
}
function c() {
console.log("function c");
}
function callFunction(ref) {
setTimeout(function(){
ref();
},5000);
}
callFunction(a);
callFunction(b);
callFunction(c);
/* These are anonymous function. These will never wait for each other ro execute.*/
setTimeout(function(){a();},5000);
setTimeout(function(){b();},5000);
setTimeout(function(){c();},5000);

Before we start, as its common misconception, you must know that setTimeout time passed doesn't mean it will be executed exactly after 100ms. It can be longer (just not earlier). You should definitly watch a great talk by Philip Roberts - What the heck is the event loop anyway?.
Edit - as my answer covers setTimeout-way I think the answer given by #Adam Kettani is what you need, as with promises you can be sure the code will be executed in the right time and order, and it is also more clean what is going on.
Okay, let's get down to business. You can put them in array and then use a `forEach
const functions = [
function (){
console.log('a');
},
function (){
console.log('b');
},
function (){
console.log('c');
},
];
functions.forEach(fn => setTimeout(fn, 1000));
Keep in mind that they all will be set with timeout 1000ms, so they will most likely execute at the same time. If you want to have a delay in-between too just modify forEach:
const functions = [
function (){
console.log('a');
},
function (){
console.log('b');
},
function (){
console.log('c');
},
];
functions.forEach((fn, index) => setTimeout(fn, index * 2000));
To make this generic you can extract this line of code to a function:
const functions = [
function (){
console.log('a');
},
function (){
console.log('b');
},
function (){
console.log('c');
},
];
function _setTimeout (fn, delay) {
// setTimeout returns a value that allows you to
// cancel timeout, so it would be great if our function
// has this feature of converting array of functions
// to array of timeout ids
return fn.reduce((timeoutIds, fn, index) => {
return [...timeoutIds, setTimeout(fn, index * delay)];
}, []);
}
const timeouts = _setTimeout(functions, 2000);
console.log(timeouts);
clearTimeout(timeouts[2]);
console.log('C shall not pass!');

Related

How setTimeout works?

I have a concern with setTimeout function in javascript. when we call setTimeout function without return anything, it is okay for me. like
setTimeout(function() {
console.log("ok function called")
},2000);
here in the above example it just simply call that function after 2000ms,
And if I write this like
setTimeout(function(params) {
console.log("passed value is"+params)
},2000,55);
now it will call this function with 55 as an argument, right?
But problem is that when I call to write this like
setTimeout(function(params) {
console.log("passed value is"+params)
}(55),2000);
here function is calling with 55 as params but it is now waiting for 2000ms
And when I wrote like
setTimeout(function(params) {
console.log("passed value is "+params);
return function(){
console.log(params)
};
}(55),2000);
in this only return function is calling with 2000ms delay, the line console.log("passed value is "+params); is executing instantly
please help me get out of this problem.
One is a function. Another is a function call.
First, let's forget javascript for now. If you know any other programming language, what do you expect the two pieces of code below to do?
function a () { return 1 }
x = a;
y = a();
What do you expect x to be? 1 or a pointer to function a?
What do you expect y to be? 1 or a pointer to function a?
A function is not a function call. When you call a function it returns a value.
Now let's switch back to javascript. Whenever I get confused by a piece of code, I try to make the syntax simpler so that I can understand what's going on:
setTimeout(function() {console.log("ok function called")}, 2000);
Now, that's a compact piece of code, let's make the syntax simpler. The above code is the same as:
var a = function() {console.log("ok function called")};
setTimeout(a, 2000);
So what does that do? It will call the function a after 2 seconds.
Now let's take a look at:
setTimeout(function() {console.log("ok function called")}(), 2000);
// Note this ----------^^
That's the same as:
var b = function() {console.log("ok function called")}();
setTimeout(b, 2000);
which can further be simplified to:
var a = function() {console.log("ok function called")};
var b = a();
setTimeout(b, 2000);
So I hope you see what you're really passing to setTimeout. You're passing the return value of the function, not the function.
When you write
setTimeout(function (params) { return something; }(55), 2000);
what actually happens is something like this:
var _temp_func = function (params) { return something; };
var _temp = _temp_func(55);
setTimeout(_temp, 2000);
The anonymous function you have as a parameter to setTimeout is evaluated immediately, even before the call to setTimeout itself. In contrast to that, the actual parameter that ends up in _temp here is called with a delay. This is what happens in your last example.
setTimeout takes only function name without parenthesis.
correct syntax : setTimeout(Helloworld) - here you are setting function
incorrect syntax : setTimeout(HelloWorld()) - here you are calling function
or non IIFE function.
It's an IIFE that you are passing hence it is getting called immediately.
setTimeout(function (params) { return something; }(55), 2000);

Chain multiple AJAX calls with delay and passing variables

I'm working on a way to chain a set of 3 ajax calls per variable against an array of data with some delay in between.
Taking into account this answer.
I'm trying to update the code to achieve the following:
Add a delay in the b() and c() function
Pass a variable from a() to b() and from b() to c()
Is there a way I can pass a variable a() would generate to b() without using global variables? If not that's fine, I'd just like to know.
And how exactly can I get b() to be delayed for several seconds before processing c()? I would assume adding in a setTimeout would work as it's waiting for the promise before it starts c(), but this is not the case.
jsfiddle
function a(user, pass) {
return $.post('/echo/json/', {}, function(re){
console.log(1);
});
}
function b() {
setTimeout(function() {
return $.post('/echo/json/', {}, function(re){
console.log(2);
});
}, 3000);
}
function c() {
console.log(3);
}
var data = [{u: 'au', p: 'ap'}, {u: 'bu', p: 'bp'}];
var counter = 0;
function main() {
if(counter < data.length) {
$.when(a(data[counter].u, data[counter].p).then(b).then(c)).done(function(){
counter++;
main();
})
}
}
main();
To ensure that c() isn't executed until after the timeout code has been called, create your own promise and return it from the b() function. You should wrap the setTimeout function in this promise, and call the resolve(res) method to notify the .then() functions watching the promise, passing an object representing the data or body of the response.
function b(dataFromA) {
return new Promise((resolve, reject) => {
setTimeout(function() {
return $.post('/echo/json/', {}, res => {
let dataToB = res;
console.log(2);
resolve(dataToB);
});
}, 3000);
});
}
Note that b() now accepts data that can be passed from the response of the a() promise. You can manipulate this data inside the b(res) function or in the promiseFromA.then(res => { // ... Your promise callback code }); before calling b(res).
setTimeout as used in function b is not a promise. i will find some docs to site and post shortly but here is what i see.
to use a promise you need to call a promise method, setTimeout is not a promise. it is only a delay. it has to do with the event loop in javascript or in the javascript runtime to be more correct. there is some good stuff over here --> https://github.com/getify/You-Dont-Know-JS/tree/master/async%20%26%20performance
also .then only works to resolve a promise
getify really breaks it down but i would start with the javascript event loop

nested setTimeout functions when subfunctions include varying delays

I have a set of about 100 arguments that all take different amounts of time to run through a given function. Each is a brief animation on a page, animating a different part depending on the argument, and they take about 1-3 seconds each.
I checked this: Nested setTimeout alternative?
...but it only works when the subfunctions take the same amount of time,
I can collect the arguments in an array in the order they should go, i.e.:
args= [arg1, arg2, arg3, arg4...]
Currently my calls looks like this:
setTimeout(myfunction(arg1), 3000);
setTimeout(myfunction(arg2), 5000);
setTimeout(myfunction(arg3), 7500);
setTimeout(myfunction(arg4), 8500);...
I'd really like to be able to have code that says "when myfunction(arg1) is finished, wait 500 milliseconds and then execute myfunction(arg2), then when that is finished wait 500 ms and execute func3, etc."
I don't know how to incorporate that into either the running of the setTimeouts or the definition of myfunction().
Thank you.
Promises are a perfect way to chain async operations.
If you could consider changing the body of myFunction so that it returns a promise then you could chain those operation easily.
The body of myFunction would look like this
function myFunction(args, time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
// here you do your stuff
resolve(); // resolve the promise when it's done
}, time);
})
}
And you call it this way
var args = [
{ args: "", timeout: 100 },
{ args: "", timeout: 300 }
]
var promise = Promise.resolve();
args.forEach(function (animation) {
promise = promise
.then(myFunction.bind(null, animation.args, animation.timeout))
// ^ chaining promise so that they fire one after another
})
You can just schedule your next task in the callback of the previous setTimeout, like that:
var tasks = [
{ arg : "arg1", delay : 3000},
{ arg : "arg2", delay: 2000},
{ arg : "arg3", delay : 2500}
];
function myFunction(arg) {
console.log(new Date(),arg);
}
function schedule() {
var task = tasks.shift();
if(task) {
setTimeout(function() {
myFunction(task.arg);
if(tasks.length) schedule();
},task.delay);
}
}
schedule();
This code will call myFunction("arg1") in 3000ms, then myFunction("arg2") in +2000ms and then myFunction("arg3") in +2500ms.
Each time it will remove (shift) the first element of your "task list",
and then stop once it is empty.
Take a note that this code will mutate your tasks array (by removing the next task from it on an each iteration), so you won't be able to reuse it.
If that is a problem, just use an explicit index to address the next task:
function schedule(tasks,i) {
if(i<tasks.length) {
setTimeout(function() {
myFunction(tasks[i].arg);
if(i+1<tasks.length) schedule(tasks,i+1);
},tasks[i].delay);
}
}
schedule(tasks,0);
I think the easiest way to sort out this problem is a promise chain:
var args = [1, 2, 3, 4, 5, 6]
var i = 0;
function doStuff(arg) {
//do stuff
console.log(arg)
}
function getPromise(cb, arg, time){
return function() {
return new Promise(function(resolve){
setTimeout(function(){
cb(arg)
resolve()
}, time)
})
}
}
var promise_chain = Promise.resolve();
while (args[i]) {
promise_chain = promise_chain.then(getPromise(doStuff, args[i++], 500))
}
This code will generate a bunch of promises. Each one waits 500ms to resolve itself and execute next bunch of code. Hope this help.

wait for function done (with setInterval) and run next function

how to run next function after first done with setInterval?
for example:
step1();
step2();
setInterval(step1, 1000).done(function() {
setInterval(step2, 1000).done( /* next step */);
});
please help me with solution!
Edit: This is an old answer. Now you can achieve this using promises also but the code will be slightly different.
If you don't want to use a promise you can use a simple flag to achieve such a thing. Please see example below:
var flag = true;
function step1() {
console.log('title');
}
function step2() {
console.log('subtitle');
}
function wrapper() {
if(flag) {
step1();
} else {
step2();
}
flag = !flag;
}
setInterval(wrapper, 30000);
If you want to chain functions on completion you can use callback functions.
Example:
function first(callback) {
console.log('Running first');
if (callback) {
callback();
}
}
function second() {
console.log('Running second function');
}
first(second);
The first function checks if a callback is used and then runs it. If there is no callback function nothing happens. You can chain functions this way.
You can also use anonymous functions.
first(function () {
console.log('This function that will run after the first one);
});
If you use setTimeout() you can't be sure whether the previous function has completed. A better way would be to use promises.
Understanding Promises
I hope I understood your question right. Good luck!
First of all setInterval can not be done by itself, it will fire infinitely if you not clear it with clearInterval.
But if you have some async action inside your function and whant to wait for it and then call another function you may just promisify it like Avraam Mavridis suggested.
function step1() {
var deferred = $.Deferred();
setTimeout(function () {
alert('I am step 1');
deferred.resolve();
}, 1000);
return deferred.promise();
}
function step2() {
alert('I am step 2');
}
step1().done(step2);
JsFiddle

nodejs: wait for other methods to finish before executing

say I have 2 methods:
function A(callback) { ... }
function B(callback) { ... }
I want to execute:
function C();
after both A and B are finished.
what we usually do is to put function C in the callback like:
A(function() {
B(function() {
C();
});
});
now if both A and B takes a long time, I don't want B to execute after A has been finished. instead I want to start them at the same time to enhance performance.
what I'm thinking is to implement something like a semaphore (not really a semaphore of course), it fires an event after both A and B are finished. so that I can call C from within the event.
what I want to know is, is there any library implemented the above function already? I believe I'm not the first one who wants to do it.
any help is appreciated.
To expand on my comment...
async is a commonly used asynchronous flow control library for Node.js.
Its async.parallel() would probably do well for this:
async.parallel([
function(done) {
A(function () {
done(null);
});
},
function(done) {
B(function () {
done(null);
});
}
], function (err) {
C();
});
It's possible that this can be shortened, but it depends on how each function interact with callbacks and whether they follow the common Node.js pattern of error-first callbacks:
async.parallel([A, B], C);
For the sake of completeness and as mentioned above, the same result can be achieved using an external object to hold completion state where both A() and B() check to see if the other has completed and if so, invokes C(). As in:
var results={};
function onComplete(){
if(results['A'] && results['B'] && !results['C']) {
C();
}
}
function A(){
// ...
results['A']=true;
onComplete();
}
function B(){
// ...
results['B']=true;
onComplete();
}
The results object can be replaced by adding a 'isComplete' flag to both A() and B(), as in:
function A(){
// ...
A.isComplete=true;
onComplete();
}
And modifying onComplete to check this new flag:
function onComplete(){
if(A.isComplete && ...
}
Or, the same using events:
var util=require('util'),
events=require('events'),
EventEmitter=events.EventEmitter;
function F(){
EventEmitter.call(this); // init ancestor
}
util.inherits(F,EventEmitter); // assign ancestor
F.prototype.A=function(){
var self=this;
console.log('running A()');
setTimeout(function(){ // simulate long running code - 5 seconds
F.prototype.A.isComplete=true;
self.emit('complete','A');
},5000);
};
F.prototype.B=function(){
var self=this;
console.log('running B()');
setTimeout(function(){ // simulate long running code - 3 seconds
F.prototype.B.isComplete=true;
self.emit('complete','B');
},3000);
};
F.prototype.C=function(){
console.log('running C()');
};
var f=new F;
f.on('complete',function(which){ // onComplete handler
console.log(which+'() is complete');
if(F.prototype.A.isComplete && F.prototype.B.isComplete){
f.C();
}
});
// start it up
f.A();
f.B();
which, when run, will produce:
>node example.js
running A()
running B()
B() is complete
A() is complete
running C()
>
async.parallel([
function(){ ... },
function(){ ... }
], callback);
from: https://github.com/caolan/async
so in your case:
async.parallel([funcA,funcB],funcC);
//function definitions
function funcA() {...}
function funcB() {...}
function funcC() {...}
without modules i guess it would look something like this:
var numFuncs = 2;
A(D);
B(D);
and then
function D() {
if(numFuncs==0){ C(); } else {
numFuncs--;
}}
or like this:
A(D(C));
B(D(C));
function D() {
var x = process.funcsToCall= process.funcsToCall || {};
var f=arguments[0];
(!x.hasOwnProperty(f.name))?x[f.name]=0:x[f.name]++;
return function(){
(x[f.name]==0)?f():x[f.name]--;
}
}
If you're running on ES6, you can use Promise.all. Here is the example code rewritten:
Promise.all([
new Promise((resolve) => A(() => resolve())),
new Promise((resolve) => B(() => resolve())),
]).then(() => {
C()
}).catch(err => {
// handle errors from function A, B and C
})
we can aync and await for this purpose for example:
async function Foo(){
// function logic
}
and this Foo function as:
await Foo();

Categories

Resources