I want to execute several JavaScript functions in a specific order (like below) and not until the previous function has completed. I have tried this so many ways. Any suggestions? Any help is so greatly appreciated, I have been stuck on this for so long. Thanks in advance!
function savedSearch(e){
applySearch1("ColumnA");
applySearch2("ColumnB");
applySearch3("ColumnC");
applySearch4("ColumnD");
applySearch5("ColumnE");
applySearch6("ColumnF");
}
To add in response to the other answer by Mohkhan, you can also use the async library.
https://github.com/caolan/async
That will keep you out of callback hell and make for a much easier to read list of functions.
You should use callbacks in all your applySearch* functions.
Like this.
function savedSearch(e){
applySearch1("ColumnA", function(){
applySearch2("ColumnB", function(){
applySearch3("ColumnC", function(){
applySearch4("ColumnD", function(){
applySearch5("ColumnE",function(){
applySearch6("ColumnF", function(){
// You are done
});
});
});
});
});
});
}
If use jquery, it has deferred objects which helps you deal with async functions.
Here is an example:
// Code goes here
$(document).ready(function() {
function Pipe() {
this.asyncTasks = [];
this.observers = {};
this.on = function(eventName, fn) {
if (!this.observers[eventName]) {
this.observers[eventName] = $.Callbacks;
}
this.observers[eventName].add(fn);
}
this.fire = function(eventName, data) {
if (this.observers[eventName]) {
this.observers[eventName].fire(data);
}
}
this.register = function(asyncFn, context) {
this.asyncTasks.push(new Task(asyncFn, context));
}
this.start = function() {
this.fire('start');
this._next();
}
this._next = function() {
var task = this.asyncTasks.shift();
if (task) {
task.execute().then($.proxy(this._next, this));
} else {
this.fire('end');
}
}
var Task = function(fn, context) {
this.fn = fn;
this.context = context;
this.execute = function() {
if (!this.fn) {
throw new Exception("Failed to execute.");
}
var promise = this.fn.call(context);
this.fn = null;
return promise;
}
}
}
var bookMoview = function() {
var dfd = jQuery.Deferred();
// Resolve after a random interval
setTimeout(function() {
dfd.resolve("The movie is booked");
console.log("The movie is booked");
}, Math.floor(400 + Math.random() * 2000));
// Return the Promise so caller can't change the Deferred
return dfd.promise();
}
var bookTaxi = function() {
var dfd = jQuery.Deferred();
// Resolve after a random interval
setTimeout(function() {
console.log("Taxi is booked");
dfd.resolve("Taxi is booked");
}, Math.floor(400 + Math.random() * 2000));
// Return the Promise so caller can't change the Deferred
return dfd.promise();
}
var pipe = new Pipe();
pipe.register(bookMoview);
pipe.register(bookTaxi);
pipe.start();
});
Related
for example, if I need to do task s1,s2,s3 linerly,it would be look like this:
var s1=function(){
document.write("[1s task]");
setTimeout(s2,2000);
}
var s2=function(){
document.write("[2s task]");
setTimeout(s3,3000);
}
var s3=function(){
document.write("[3s task]");
}
setTimeout(s1,1000);
but it is very hard to maintain if I want to change the order from s1,s2,s3 to s3,s1,s2. How to wrap and 'objectize' a task which look like this:
mySetTimeout(new MyTask(s1,1000),new MyTask(s2,1000),new MyTask(s3,1000));
so that it is easy to change order from s1,s2,s3 to s3,s1,s2:
mySetTimeout(new MyTask(s3,3000),new MyTask(s1,1000),new MyTask(s2,2000));
? How to write mySetTimeout and MyTask?
The solution you didn't know you were looking for are promises. They're objects representing asynchronous results, and can be chained with callback functions.
function delay(t) {
return new Promise(resolve => {
setTimeout(resolve, t);
});
}
function s1() {
console.log("[1s task]");
return delay(1000);
}
function s2() {
console.log("[2s task]");
return delay(2000);
}
function s3() {
console.log("[3s task]");
return delay(3000);
}
s1().then(s2).then(s3);
Create a schedule task which takes different tasks as parameters (an example below)
function scheduleTask()
{
var args = [...arguments];
var firstTask = args.slice(0,1)[0];
args = args.slice(1);
//console.log(args, firstTask);
firstTask && setTimeout( function(){
firstTask( function(){
scheduleTask(...args);
});
}, 1000); //timeout is constant
}
scheduleTask(s1, s2, s3);
Demo
function scheduleTask()
{
var args = [...arguments];
var firstTask = args.slice(0,1)[0];
args = args.slice(1);
//console.log(args, firstTask);
firstTask && setTimeout( function(){
firstTask( function(){
scheduleTask(...args);
});
}, 1000); //timeout is constant
}
scheduleTask(s1, s2, s3);
function s1( cb )
{
console.log("s1");
cb();
}
function s2( cb )
{
console.log("s2");
cb();
}
function s3( cb )
{
console.log("s3");
cb();
}
Or as suggested by #Thomas you can shorten it by doing
function scheduleTask(firstTask, ...args)
{
firstTask && setTimeout(function() {
firstTask(function() {
scheduleTask(...args);
});
}, 1000); //timeout is constant
}
Demo
function scheduleTask(firstTask, ...args)
{
firstTask && setTimeout(function() {
firstTask(function() {
scheduleTask(...args);
});
}, 1000); //timeout is constant
}
scheduleTask(s1, s2, s3);
function s1(cb) {
console.log("s1");
cb();
}
function s2(cb) {
console.log("s2");
cb();
}
function s3(cb) {
console.log("s3");
cb();
}
I guess #Bergi's promise way is nice but you may still sequence your jobs without using promises. Just put your jobs in an array in the order you like them get processed and use a recursive sequencer.
var seqJobs = ([j,...js]) => j && setTimeout(_ => (j.job(), seqJobs(js)), j.dly),
jobs = [{job: _ => console.log("[0s task]"), dly: 500},
{job: _ => console.log("[1s task]"), dly: 2000},
{job: _ => console.log("[2s task]"), dly: 3000},
{job: _ => console.log("[3s task]"), dly: 1000}];
seqJobs(jobs);
Here is something wrong. All functions should be called synchronously. Could anyone give me a hint? I think that is an error in the for loop
Here is my code:
var radioValues = msg.options;
var cn = gotoReport()
.then(clickReport)
.then(clickReportFake)
.then(clickNext);
for (var i = 0; i < radioValues.length; i++){
cn = cn.then(clickOption(radioValues[i])).then(clickNext);
}
cn.then(clickSendToFacebook).then(clickFinish);
//all called functions look like that
function clickNext(){
return process(function(){
console.log("clickNext");
var next = $('button:contains("Weiter")');
$(next).click();
},3000);
}
function process(action, ms) {
var deferred = $.Deferred();
timer = setInterval(function() {
deferred.notify();
}, 1000);
setTimeout(function() {
clearInterval(timer);
action();
deferred.resolve();
}, ms);
// return deferred;
return deferred.promise();
}
function sleep(ms)
{
return(new Promise(function(resolve, reject) {
setTimeout(function() { resolve(); }, ms);
}));
}
Here is the output
gotoReport
clickOption=option3
clickReport
clickReportFake
clickNext
clickNext
clickSendToFacebook
clickFinish
One major issue is here:
cn.then(clickOption(radioValues[i]))
You are not passing the clickOption function as argument to then -- you are invoking it. Instead do:
cn.then(clickOption.bind(null, radioValues[i]))
I need some help...I have 5 functions in javascript and I'm not able to call the fifth function after previous functions.
I have some like this:
function one(){
}
function two(){
}
function three(){
}
function four(){
}
function five(){
}
This code, execute the function "five()" before other function. I would like that five() will be execute only after all previous functions have finish.
How can I do that?
EDIT:
This is my call
function callFunction(){
one();
two();
three();
four();
five();
}
The best solution is to use promises. The promise is great ease of asynchronous processes. You need Promise.all(iterable).
The Promise.all(iterable) method returns a promise that resolves when
all of the promises in the iterable argument have resolved, or rejects
with the reason of the first passed promise that rejects.
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "foo");
});
Promise.all([p1, p2, p3]).then(function(values) {
console.log(values); // [3, 1337, "foo"]
});
Check this:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
If you want IE compatibility you can use q.
https://github.com/kriskowal/q
q also have .all .
I write this example for you:
/**
* Example of Q.all usage
* #author Georgi Naumov
* gonaumov#gmail.com for contacts and
* suggestions.
*/
var firstStep = (function () {
var dfd = Q.defer();
setTimeout(function () {
console.log("first step finished");
dfd.resolve();
}, 1000);
return dfd.promise;
}());
var secondStep = (function () {
var dfd = Q.defer();
setTimeout(function () {
console.log("second step finished");
dfd.resolve();
}, 3000);
return dfd.promise;
}());
Q.all([firstStep, secondStep]).then(function () {
console.log('All done!');
});
console.log('All done!'); will be executed when all asinc task is finished.
Here is jsfiddle:
http://jsfiddle.net/drv4538t/3/
This solution is independent from time interval. Check this example:
/**
* Example of Q.all usage
* #author Georgi Naumov
* gonaumov#gmail.com for contacts and
* suggestions.
*/
/**
* This function is taken from:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
*/
function getRandomIntInclusive(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var firstStep = (function () {
var dfd = Q.defer();
setTimeout(function () {
console.log("first step finished");
dfd.resolve();
}, getRandomIntInclusive(1000, 10000));
return dfd.promise;
}());
var secondStep = (function () {
var dfd = Q.defer();
setTimeout(function () {
console.log("second step finished");
dfd.resolve();
}, getRandomIntInclusive(1000, 10000));
return dfd.promise;
}());
Q.all([firstStep, secondStep]).then(function () {
console.log('All done!');
});
And here is the jsfiddle:
http://jsfiddle.net/drv4538t/4/
Where is your call ?? Is the process asynchronous ?
else simply call :
one();
two();
...
five();
EDIT
Since they are async functions, you have to execute the next function at the end of the previous async process like that :
function one(){
setTimeout(function(){
//Do async process
two();
}, 1000);
}
function two(){
setTimeout(function(){
//Do async process
three();
}, 1000);
}
function three(){
setTimeout(function(){
// etc...
}, 1000);
}
one();
One simple solution can be:
function one(){
console.log('one')
}
function two(){
console.log('two')
}
function three(){
console.log('three')
}
function four(){
console.log('four')
}
function five(){
console.log('five')
}
['one','two','three','four','five'].forEach(function(fun){
window[fun]();
})
/* declare functions */
function one(){
two()
}
function two(){
three()
}
function three(){
four()
}
function four(){
five()
}
function five(){
}
/* call function */
one()
you can set a boolean to true for every function you want to finish before running function 5. Then try to run function 5 at the end of every function...if all functions have finished and function 5 didn't run yet, you run function 5.
var f1Finished = false;
var f2Finished = false;
var f3Finished = false;
var f4Finished = false;
var ran5 = false;
function allFinished() {
return f1Finished && f2Finished && f3Finished && f4Finished;
}
function one(){
f1Finished = true;
if(allFinished())
five();
}
function two(){
f2Finished = true;
if(allFinished())
five();
}
function three(){
f3Finished = true;
if(allFinished())
five();
}
function four(){
f4Finished = true;
if(allFinished())
five();
}
function five(){
if(!ran5) {
ran5 = true;
//...
}
}
one();
two();
three();
four();
There is great article i found that clears the concept of callback function in Jquery.
http://www.impressivewebs.com/callback-functions-javascript/
Sample:
function mySandwich(param1, param2, callback) {
alert('Started eating my sandwich.\n\nIt has: ' + param1 + ', ' + param2);
callback();}
mySandwich('ham', 'cheese', function() {
alert('Finished eating my sandwich.');
});
This is how I would do it
function callFunction(){
one();
Await();
two();
Await();
three();
Await();
four();
Await();
five();
}
function Await(){
for(var i=0;i<100000;i++){
}
}
You can also fine tune the wait funtion
I'm trying to create a function queue with several functions in it.
After the creation i want to execute each function in it's turn.
But these function have delayed instructions inside of them, so i want to wait for each of the functions to complete its execution before the continuing.
My attempts:
var funqueue = [];
funqueue.push( function() {fun1() });
funqueue.push( function() {fun2() });
funqueue.push( function() {fun3() });
executeFunctionQueue(funqueue);
Where the execute function is:
function executeFunctionQueue(funqueue){
var fun1=funqueue.pop;
$.when(fun1()).then(executeFunctionQueue(funqueue));
}
But this does not work.
How should i do it?
Try utilizing .queue() , .promise() ; see also Change easing functions on animations in jQuery queue
function fun1() {
return $.Deferred(function(dfd) {
setTimeout(function() {
dfd.resolve(1)
}, 1500)
}).promise().then(msg)
}
function fun2() {
return $.Deferred(function(dfd) {
setTimeout(function() {
dfd.resolve(2)
}, 1500)
}).promise().then(msg)
}
function fun3() {
return $.Deferred(function(dfd) {
setTimeout(function() {
dfd.resolve(3)
}, 1500)
}).promise().then(msg)
}
var funqueue = [];
funqueue.push(function() {
return fun1()
});
funqueue.push(function() {
return fun2()
});
funqueue.push(function() {
return fun3()
});
function msg(data) {
if (data === "complete") console.log(data)
else $("body").append(data + "<br>")
}
function executeFunctionQueue(funqueue) {
var deferred = funqueue.pop();
return deferred().then(function() {
// set `this` within `$.queue()` , `.then()` to empty object `{}`,
// or other object
return $({}).queue("fun", $.map(funqueue, function(fn) {
return function(next) {
// return `next` function in `"fun"` queue
return fn().then(next)
}
})).dequeue("fun").promise("fun")
.then(function() {
// return "complete" string when `fun` queue empty
return "complete"
})
});
}
executeFunctionQueue(funqueue)
.then(msg);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
Alternatively , using $.when()
function executeFunctionQueue(funqueue) {
return $.when(!!funqueue[funqueue.length - 1]
? funqueue.pop().call().then(function() {
return executeFunctionQueue(funqueue)})
: "complete")
}
executeFunctionQueue(funqueue)
.then(function(complete) {
console.log(complete)
});
function fun1() {
return $.Deferred(function(dfd) {
setTimeout(function() {
dfd.resolve(1)
}, 1500)
}).promise().then(msg)
}
function fun2() {
return $.Deferred(function(dfd) {
setTimeout(function() {
dfd.resolve(2)
}, 1500)
}).promise().then(msg)
}
function fun3() {
return $.Deferred(function(dfd) {
setTimeout(function() {
dfd.resolve(3)
}, 1500)
}).promise().then(msg)
}
var funqueue = [];
funqueue.push(function() {
return fun1()
});
funqueue.push(function() {
return fun2()
});
funqueue.push(function() {
return fun3()
});
function msg(data) {
if (data === "complete") console.log(data)
else $("body").append(data + "<br>")
}
function executeFunctionQueue(funqueue) {
return $.when(!!funqueue[funqueue.length - 1]
? funqueue.pop().call().then(function() {
return executeFunctionQueue(funqueue)})
: "complete")
}
executeFunctionQueue(funqueue)
.then(msg);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
If you have functions that return Promises, this can be done very simply with a function like sequence:
// sequence :: [(undefined -> Promise<undefined>)] -> Promise<undefined>
function sequence(fns) {
var fn = fns.shift();
return fn ? fn().then(sequence.bind(null, fns)) : Promise.resolve(undefined);
}
sequence assumes that your asynchronous/Promise-returning functions do not take any inputs and do not produce any outputs (that they are merely being called for side-effects.)
An example usage of the sequence function is:
sequence([f1, f2, f3]);
function f1() {
return new Promise(function (res) {
setTimeout(function () {
console.log('f1');
res();
}, 100);
});
}
function f2() {
return new Promise(function (res) {
setTimeout(function () {
console.log('f2');
res();
}, 1100);
});
}
function f3() {
return new Promise(function (res) {
setTimeout(function () {
console.log('f3');
res();
}, 10);
});
}
This will log out 'f1', 'f2', and 'f3' in order with the varying, specified time delays in between.
Use this
function executeFunctionQueue(funqueue){
if(!funqueue.length){
return
}
var fun1=funqueue.pop();
$.when(fun1()).then(function(){
executeFunctionQueue(funqueue)
});
}
Or even this if queued functions are not asynchronous.
function executeFunctionQueue(funqueue){
var fun=funqueue.pop();
fun()
if(!funqueue.length){
return
}
executeFunctionQueue(funqueue);
}
First create an array of functions as given:
var array_of_functions = [function1, function2, function3, function4];
When you want to execute a given function in the array try this:
array_of_functions[index]('mystring');
use deferred/promise pattern to execute functions on other function complete.
var createQueue = function () {
var d = $.Deferred(),
p = d.promise(),
triggerQueue = function () {
d.resolve();
};
return {
addToQueue: p.then,
triggerQueue: triggerQueue
}
};
var cq = createQueue();
cq.addToQueue(function () {
console.log("hi");
}).then(function () {
console.log("hello");
});
cq.triggerQueue();
In order to make a clean queue, your asynchronous functions will need to somehow signify when they are done, or the next function won't know when to begin. This means you cannot pass in just any old function; they'll need to follow some format. I'd suggest taking a done callback as the first parameter in your function calls. This way, you can support both synchronous and asynchronous functions.
var processQueue = function nextStep(queue) {
var next = queue.shift();
next && next(function() { nextStep(queue); });
}
function fun1(done) {
setTimeout(function() {
console.info('1');
done();
}, 1000);
}
function fun2(done) {
console.info('2');
done();
}
processQueue([fun1, fun2]);
// >> 1 second wait
// >> 1
// >> 2
I some problems understanding how to use "q" (https://github.com/kriskowal/q) a promises library for javascript:
var delayOne = function() {
setTimeout(function() {
return 'hi';
}, 100);
};
var delayTwo = function(preValue) {
setTimeout(function() {
return preValue + ' my name';
}, 200);
};
var delayThree = function(preValue) {
setTimeout(function() {
return preValue + ' is bodo';
}, 300);
};
var delayFour = function(preValue) {
setTimeout(function() {
console.log(preValue);
}, 400);
};
Q.fcall(delayOne).then(delayTwo).then(delayThree).then(delayFour).end();
this only returns undefined...
As wroniasty pointed out, you need to return a promise from each of those functions, but you should also abstract any callback oriented APIs (like setTimeout) as much as possible and use APIs that return promises instead.
In the case of setTimeout, Q already provides Q.delay(ms) which returns a promise that will be resolved after the specified number of milliseconds, perfect for replacing setTimeout:
var delayOne = function() {
return Q.delay(100).then(function() {
return 'hi';
});
};
var delayTwo = function(preValue) {
return Q.delay(200).then(function() {
return preValue + ' my name';
});
};
var delayThree = function(preValue) {
return Q.delay(300).then(function() {
return preValue + ' is bodo';
});
};
var delayFour = function(preValue) {
return Q.delay(400).then(function() {
console.log(preValue);
});
};
Q.fcall(delayOne).then(delayTwo).then(delayThree).then(delayFour).done();
(note: end has been replaced with done)
The reason you get "undefined" is because the functions you are chaining are not returning anything:
var delayOne = function() {
setTimeout(function() {
return 'hi';
}, 100);
};
delayOne calls setTimeout, and returns nothing (undefined).
To achieve your goal you must use Q.defer:
var delayOne = function() {
var d = Q.defer();
setTimeout(function() {
d.resolve("HELLO");
}, 100);
return d.promise;
};
var delayTwo = function(preValue) {
setTimeout(function() {
alert(preValue);
},
400);
};
delayOne().then ( delayTwo );
http://jsfiddle.net/uzJrs/2/