What is the best way to fire a function once another has finished?
At the moment I have 6 functions that I'm calling on DOM load like this:
$(document).ready(function(){
func1();
func2();
func3();
func4();
func5();
func6();
});
function func1(){
do some stuff
}
function func2(){
do some stuff
}
function func3(){
do some stuff
}
function func4(){
do some stuff
}
function func5(){
do some stuff
}
function func6(){
do some stuff
}
But I want them to fire one after another. How would I do this?
Thanks in advance
Try by using callbacks like,
$(document).ready(function(){
func1(func2);
});
function func1(callback){
do some stuff
callback('func2');
}
function func2(callback){
do some stuff
callback('func3');
}
function func3(callback){
do some stuff
callback('func4');
}
function func4(callback){
do some stuff
callback('func5');
}
function func5(callback){
do some stuff
callback('func6');
}
function func6(callback){
do some stuff
}
Read callback-functions-javascript
You can refer Is there a better way to do callback chaining in javascript? for chained callbacks
function func1(){
do some stuff
_next();
}
function func2(){
do some stuff
_next();
}
function func3(){
do some stuff
_next();
}
function func4(){
do some stuff
_next();
}
function func5(){
do some stuff
_next();
}
function func6(){
do some stuff
_next();
}
function chainCallbacks() {
var _this = this;
var _counter = 0;
var _callbacks = arguments;
var _next = function() {
_counter++;
if(_counter < _callbacks.length) {
_callbacks[_counter].apply(_this);
}
};
_this._next = _next;
return function() {
if(_callbacks.length > 0) {
_callbacks[0].apply(_this);
}
};
}
var queue = chainCallbacks(func1, func2, func3,func4,func5,func6);
queue();
The way you wrote it is correct for synchronous code. However, based on your comment it sounds like you are firing off external requests that run asynchronously. What happens in this case is that function1 may fire off some code accessing Sharepoint and then will complete the rest of the code in function 1 after that...and then flow right into function2 without waiting to see what happens with the Sharepoint request.
My preferred way of dealing with this would be using callbacks from the asynchronous operations. Once you pull that data from Sharepoint, for instance, you are going to call some other function (we'll call it Sharepoint_callback1). Add a call to that function:
$(document).ready(function(){
func1();
});
function func1(){
do some stuff that calls Sharepoint, which after complete calls Sharepoint_callback1
}
function func2(){
do some stuff
}
function Sharepoint_callback1() {
do some stuff
func2();
}
There are other methods of doing this. JQuery provides callback handlers for almost of its operations, but it all essentially boils down to the same thing as above.
If I misunderstood the question I apologize; please post additional details and I'll modify my answer.
You could write a queue function. For queue of functions you can use array:
var fn1 = function() {},
fn2 = function() {},
MyQ = [];
//add functions to array
MyQ.push(fn1);
MyQ.push(fn2);
//remove and call the first item of an array
(MyQ.shift())();
If you want use your function with scope and arguments, you can wrap functions, for example:
MyFnWithParam = function(fn, scope, params){
scope = scope || window;
params = params || [];
return function() {fn.apply(scope, params)};
};
var fn1 = MyFnWithParam(fn, this, params),
fn2 = MyFnWithParam(fn, this, params),
MyQ = [];
MyQ.push(fn1);
MyQ.push(fn2);
while (MyQ.length > 0) {
(MyQ.shift())();
}
Related
I have a function called "destination" nested in scrip1.js file. If I add this file at the end of webpage using , how can I trigger it at the next step? Here are some contents of script1.js.
script1.js
$.something = function(element, options) {
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
}
$("body").on("click", ".notify-btn", function (event) {
event.preventDefault();
destination(some args);
});
someOtherFunction();
start();
}
$.fn.something = function (options) {
return this.each(function () {
if (undefined == $(this).data("something")) {
var plugin = new $.something(this, options);
$(this).data("something", plugin);
}
});
};
I tried this, but is not working. Chrome console is showing error about this function.
<script type="text/javascript" src="script1.js"></script>
<script>
$.fn.something().destination();
</script>
I can not change this script1.js, so any possible way?
There's no specific connection between variables declared during function execution - and how the rest of the world sees the result of execution. So this code:
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
}
start();
... lets destination value (remember, functions in JS are first-class citizens) go away when start() completes its execution. That's actually quite convenient if you want to encapsulate some implementation details and hide it from users; this technique (also known as Module pattern) was often used in pre-class world to implement private properties in vanilla JavaScript.
However, all the values returned from a function can be reused. For example, here...
$.something = function(element, options) {
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
return {
destination
};
}
return start();
}
... you make destination function a part of object that is returned from start(). Now $.something returns an object, too; that means it can be reused:
var plugin = new $.something(this, options);
// ...
plugin.destination('some', 'args');
If you're afraid changing the return value might hurt someone, you can try to assign value of destination to $.something object itself as its property, like this:
$.something = function(element, options) {
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
return destination;
}
// ...
const destination = start();
$.something.destination = destination;
}
The returned value is not modified, yet function is accessible. Still, that's not actually a good workaround; the biggest issue is that any subsequent calls on $.something will rewrite the value of that function, which might be not a good thing if its execution depends on some scoped variables.
While technically there's a way to fetch destination function code by parsing $.something source code, I really doubt it's worth the effort in your case.
I think there is an easy solution for this, but for some reason I am not getting the expected results. My functions look like this:
var functionA = function(callback) {
loadData(fromURL1); // takes some time
loadData(fromURL2); // takes some time
callback(); // Should be called AFTER the loadData() functions are finished
}
var myCallBackFunction = function() {
// this function is called AFTER functionA() is finished
alert("All my loaded data from URL1 and URL2");
}
window.onload = function() {
functionA(myCallBackFunction);
}
Unfortunately, the callback() function above doesn't wait for loadData() to finish, and then just calls the alert with empty data.
I read a lot of online examples, but I think I am still missing something obvious.
If the loadData()s are async operations, you can do two things:
Using $.ajaxComplete():
var functionA = function(callback) {
loadData(fromURL1); // takes some time
loadData(fromURL2); // takes some time
$.ajaxComplete(function () {
callback(); // Should be called AFTER the loadData() functions are finished
});
}
Or chaining the functions:
var functionA = function(callback) {
loadData(fromURL1, function () {
loadData(fromURL2, function () {
callback(); // Should be called AFTER the loadData() functions are finished
}); // takes some time
}); // takes some time
}
I need for a function to be executable only after an object is defined, I'm currently working in a fascade pattern and one method is dependent on another method. in this case 'addNewLayer' fails because 'setFullMap' hasn't finished executing. is there a solution? I'm using jquery and vanilla js so most any solution would be helpful at this point:
var jen = (function(){
function setFullMap(mapID){
jen.map = new Map(mapID);
}
function setLayer(opt){
//execute code here after jen.map is defined
}
return{
samp: function(id, opt){
setFullMap(id);
addNewLayer(opt);
}
};
})();
Thanks
solution:
var jen = (function(){
function setFullMap(mapID, callback) {
jen.map = new Map(mapID);
if(jen.map){
callback();
}
}
return {
samp: function(id, opt){
setFullMap(id, function(){
addNewLayer(opt);
}.bind(this));
}
};
})();
You will have to pass a callback function to setFullMap, and execute it once the function has completed (at the very end, before the closing }).
var jen = (function(){
function setFullMap(mapID, callback){
jen.map = new Map(mapID);
callback();
}
function setLayer(opt){
//execute code here after jen.map is defined
}
return{
samp: function(id, opt){
setFullMap(id, function() {
addNewLayer(opt);
}.bind(this));
}
};
})();
Do not forget using .bind(this) - it is very important in order to keep the original this in your callback function.
Edit:
Actually that would not work work if the Map constructor is a-synchronous. If you do not have access to the constructor and/or you cannot pass it a callback, then presumably the only (and sad) option would be to use a setTimeout or (easier) setInterval, continuously checking at defined intervals if the operation has been completed, and then fire the callback.
You could use a callback parameter:
function setFullmap(mapId,callback) {
jen.map = new Map(mapId);
callback();
}
....
samp: function(id, opt){
setFullMap(id,function() {
addNewLayer(opt);
});
}
When u dont have a way to manipulate the Map Object then u need to use a loop:
var loop=self.setInterval(function(){
if(jen.map) {
//execute code here after jen.map is defined
console.log(typeof jen.map);
window.clearInterval(loop);
}
},50);
Check jsfiddle:
http://jsfiddle.net/9yv5t/1/
I have checked the docs and it seems that there are various events you could listen to.
For example:
var m = new Map(...);
m.on('load', function () {
//execute code when the first layer is ready
});
var l = new Layer(...);
l.on('load', function () {
//execute code when the layer has been initialized
});
It's also carefully stated for the Layer.load event:
fires after layer properties for the layer are successfully populated.
This event must be successful before the layer can be added to the
map.
I have a JavaScript function like the following.
function changeTheDom(var1, var2, var3) {
// Use DWR to get some server information
// In the DWR callback, add a element to DOM
}
This function is called in a couple of places in the page. Sometimes, in a loop. It's important that the elements be added to the DOM in the order that the changeTheDom function is called.
I originally tried adding DWREngine.setAsync(false); to the beginning of my function and DWREngine.setAsync(true); to the end of my function. While this worked, it was causing utter craziness on the rest of the page.
So I am wondering if there is a way to lock the changeTheDom function. I found this post but I couldn't really follow the else loop or how the lockingFunction was intended to be called.
Any help understanding that post or just making a locking procedure would be appreciated.
Don't try to lock anything. The cleanest way is always to adapt to the asynchronous nature of your code. So if you have an asynchronous function, use a callback. In your particular case I would suggest that you split your function up in one part that is executed before the asych call and one part that is executed afterwards:
function changeTheDomBefore(var1, var2, var3) {
//some code
//...
asyncFunction(function(result){
//this will be executed when the asynchronous function is done
changeTheDomAfter(var1, var2, var2, result);
});
}
function changeTheDomAfter(var1, var2, var3, asynchResult) {
//more code
//...
}
asyncFunction is the asynchronous function which, in this example, takes one argument - the callback function, which then calls your second changeTheDom function.
I think I finally got what you mean and I decided to create another answer, which is hopefully more helpful.
To preserve order when dealing with multiple asynchronous function calls, you could write a simple Queue class:
function Queue(){
var queue = [];
this.add = function(func, data) {
queue.push({func:func,data:data});
if (queue.length === 1) {
go();
}
};
function go() {
if (queue.length > 0) {
var func = queue[0].func,
data = queue[0].data;
//example of an async call with callback
async(function() {
func.apply(this, arguments);
queue.shift();
go();
});
}
}
};
var queue = new Queue();
function doit(data){
queue.add(function(result){
console.log(result);
}, data);
}
for (var i = 0; i < 10; i++) {
doit({
json: JSON.stringify({
index: i
}),
delay: 1 - i / 10.0
});
}
FIDDLE
So everytime you invoke your async function, you call queue.add() which adds your function in the queue and ensures that it will only execute when everything else in the queue is finished.
How can i overload the calling process of any function?
In my web app i want to do something before the call of a function and something after it how can i do this without prototyping the call method ( because i tried this and it will work only if i call a function as myFunction.call() ) and still have the requested effect.
I have tried everything for making it work, but nothing works, and to do it the hard way ( by call method ) it's non-practicable because i would have to rewrite all my code.
Could someone help please?
You can change each function definition manually.
You can change each function call manually.
If either of these refactorings is out of the scope of your problems then you're in a spot of bother.
There is no generic way that I'm familiar with to solve your problem.
However if your functions are globally accessible or namespaced then you can do the following quite easily (and can make it much more generic by parametrising the pre and post functions etc.):
NS = {
foo : function(){ console.log('foo'); },
bar : function(){ console.log('bar'); }
};
// <-- new code goes here
NS.foo();
NS.bar();
// new code below, that should go after definitions but before the calls
(function(){
var pre = function(){ console.log('pre'); },
post = function(){ console.log('post'); };
for (var fn in NS) {
NS[fn] = (function(fn){ return function(){ pre(); fn(); post(); }; })(fn);
}
})();
You can create a caller function that accept the function name, the parammeters and the context as parameters:
function pre() {
alert("I'm before the call");
}
function post() {
alert("I'm after the call");
}
function caller(func, parameters, context) {
pre();
func.apply(context, func, parameters.split(','));
post();
}
Or use AnthonyWJones solution on Calling dynamic function with dynamic parameters in Javascript that can be called this way caller(funcName, param1, param2);:
function caller(func){
pre();
this[func].apply(this, Array.prototype.slice.call(arguments, 1));
post();
}