Execute a function after for loop is completed - javascript

I have looked at several examples of callback functions but they don't seem to answer my question.
I would like myFunction2() (see below code) to be executed after the for loop is completed, unfortunately this is being called before for loop is completed (possibly due to API calls in for loop).
Can someone please advise how I can ensure that myFunction2() is called only after the completion of for loop.
function myFunction(){
for(var i =0; i<array1.length; i++){
// contains code with API calls
}
myFunction2();
}

You could substitute $.when() using .apply(), $.map() for for loop
$.when.apply($, $.map(array1, function(request) {
// do api stuff
return $.ajax(request)
}))
// call `myFunction2` when all api stuff completed
.then(myFunction2
// handle error of api call
, function err(jqxhr, textStatus, errorThrown) {
console.log(errorThrown)
})

Assuming you are using $.ajax you can use array of promises for each call and use $.when() to execute when all those promises are resolved.
function myFunction(){
var promises = array1.map(function(arrayElement){
// arrayElement is same as array1[i] in your loop
var data = // get what you need from arrayElement
// return the promise that is returned from $.ajax`
return $.get(url, data).done(function(resp){
// do whatever you do with the response
});
});
$.when.apply(null, promises).done(function(){
// code here gets called whan all api requests have successfully completed
myFunction2();
}).fail(function(err){
// not all requests succeeded
})
}

This happens because the API is called asynchronously and the JavaScript function is finished till the result from API call gets back,
The simplest solution is by callback. Just give that API call a callback function to execute when it returns, but since you didn't give the API call code, there is one more method to do it.
Make the API code synchronous. It's not recommended to make API calls synchronous because it'll block the rest of the code from working if API call takes a lot of time, but it's possible.
For example: jQuery.ajax() has async (default: true) property which if set to false makes ajax request synchronous.
NOTE: async is deprecated so don't use it, I just told you because it's a way to do it. Use the callback functions like success or fail!
like this (assuming API call is ajax):
$.ajax({
method: "POST",
url: "some.php",
data: { name: "John", location: "Boston" },
success: function2;
})
Hope this answers your question, if not then paste your API call code here.

function two called after loop finish it's process. or you can use count to ensure length and count of loop traverse are equal. then and then only call function 2
<html>
<head>
<title>win_load_vs_doc_load</title>
<script type="text/javascript" src="assets/js/jquery-2.1.4.js"></script>
</head>
<script type="text/javascript">
$arr=["a","a1","a2","a3"];
myFunction();
function myFunction()
{
for(var i =0; i<=$arr.length; i++)
{
if(i==$arr.length)
{
myFunction2();
}
else
{
alert(i);
}
}
}
function myFunction2()
{
alert("myFunction2 called");
}
</script>
</html>

Related

ajax interface without then

I want to package a ajax call into an interface without then.
If i do like this, it will just return 'No ajax return';
var ajaxReturn = ajaxFunction();
function ajaxFunction(){
var text = 'No ajax return';
// get fileName using an ajax get
$.ajax();
return text;
}
If i do like this, it will be ugly for using then;
function ajaxFunction(){
var text = 'No ajax';
var dtd = $.Deferred();
$.ajax();
return dtd.promise();
}
$.when(ajaxFunction()).then();
I just want the interface to be simple and return the right thing, can i?
//return the right
var ajaxReturn = ajaxFunction();
function ajaxFunction(){
var text = 'No ajax';
var dtd = $.Deferred();
$.ajax();
return dtd.promise();
}
$.when(ajaxFunction()).then();
Whoa, what is all that? You do need .then but you don't need most of the surrounding stuff. $.ajax generates a promise for you. You don't need to make a promise object yourself. In fact, often the only reason you need to manually set up a Deferred/Promise directly is if you're using some library that sets up callbacks and doesn't use promises itself.
function ajaxFunction(){
return $.ajax();
}
ajaxFunction().then(function(data) { ... });
Now, let's say that you didn't actually want to return the JSON structure on the end of the ajax function; you want to take out just a number from inside of it, or tweak one value to make it an easier-to-use function for its callers. Easy enough:
function ajaxFunction(){
return $.ajax().then(function(data) {
return data[12].number;
}
}
ajaxFunction().then(function(number) { ... });
In direct answer to your question: No, what you asked for isn't possible. Whenever your JavaScript methods are running, the browser can't process other events like clicks and even basic scroll operations. So, any long-running operations (like contacting the server) do not return straight away, and instead offer a callback operation.
Well..., ajax is asynchronous so you either use .then() or use a callback logic... Doing synchronous ajax is not a option for me, so I won't even mention it.
The alternative to .then() would be something like this:
ajaxFunction(function(res){ // pass a function into it
// this will be called when the ajax is done
alert(res);
});
function ajaxFunction(callback){
// get fileName using an ajax get
$.ajax({
success: callback
});
}
But again, maybe you can use just a normal ajax callback pattern anyway
$.ajax({
...
success: function(res){
// use the res
}
});
Ajax is asynchronous. then is designed to make writing async operations look more similar to synchronous code and can actually be very elegant.
Additionally, $.ajax() returns a promise and is well suited to be written as follows:
function ajaxFunction(){
return $.ajax();
}
ajaxFunction().then(function(response){
// do whatever you want with the response
})
You simply can't write asynchronous code that way (ajaxResult = ajaxFunction()). The interpreter is going to keep trucking along line by line and ajaxResult will not be ready in time.
Read up on chaining $.Deferred's. It will really clean up your async code.

How to 'chain' JS function after the first is fully done

I have a functions which should run one AFTER the other, such:
function cutTomatoesAlone(Kg){
// slice my stuff
}
function cookTomatoes(Minutes){
// boil my stuff
}
I call them such:
cutTomatoesAlone(15) // 15kg, need 3 hours!
cookTomatoes(10); // need 10 minutes
But the cookTomatoes(10) finish before my cutTomatoesAlone(15).
How to run cutTomatoesAlone(15) first and when finished, then run cookTomatoes(10) ?
Edit: cutTomatoesAlone() load an external JSON. cookTomatoes(10) work on it.
Learn about promises and deferred objects. Every Ajax function in jQuery returns a promise, so you can easily chain your function calls.
For example:
function cutTomatoesAlone(Kg) {
return $.getJSON(...); // return the promise provided by $.getJSON
}
// called as
cutTomatoesAlone(15).then(function() { // attach callback
cookTomatoes(10);
});
In case of an Ajax call, the promise is resolved once the response was successfully retrieved.
You need the method The setTimeout() which will wait the specified number of milliseconds, and then execute the specified function.
function cutTomatoesAlone(Kg){
// slice my stuff
setTimeout(function() {
cookTomatoes(10)
}, delay);
}
If your functions are independent, it should work the way you expect, assuming you're not doing stuff like making http get requests asynchronously.
If you are, what you need to do is call the second function when the first one returns from its request, using JQuery's $.done() function.
Give cutTomatoesAlone a callback.
var cookingTimePerKg = 10;
function cutTomatoesAlone(Kg, Callback) {
// slice my stuff
// when done and a callback is defined do the callback
if(Callback) Callback(Kg*cookingTimePerKg);
}
Then you could do the following:
cutTomatoesAlone(15, cookTomatoes);
The callback could also be fired on the onComplete of the (potential) XHR request.
Some Function object prototype tuning would make it easier to read
Function.prototype.after = function(callback){
this();
if( typeof(callback) == "function")
callback();
}
a = function(){alert(1)};
a.after( function(){alert(2)} )
So with cooking subject:
var cutThem = function(){
cutTomatoesAlone(15) // 15kg, need 3 hours!
}
cutThem.after( function(){
cookTomatoes(10);
});
this is a proposal for general purpose, when ajax loads are on the game it's better to use their "whenDone" option to supply them a callback.
$("#basket").load("url.extension", {kilos: kg},
function(){
cookTomatoes(10);
});

Synchronous function calls involving post json calls where one function should succeed upon the success of another function

I have two functions one of which includes multiple json call which are post by nature.
I want these to be synchronous. That is, one should run only upon the completion of the previous post (and if all posts are done and successful I want the second function to fire).
The code structure is somewhat like this:
$.getSomeData = function() {
$.postJSON("iwantdata.htm",{data:data},function(data)){
});
$.postJSON("iwantmoredata.htm",{data:data},function(data)){
});
});
$.useSomeData = function() {
});
The useSomeData must work upon subsequent json calls.
Can anyone please help me? Thanks in advance.
So basically you want something like this:
function chainPost(url1, url2, initialInput, func) {
$.post(url1, {data: initialInput})
.done(function (initialOutput) {
$.post(url2, {data: initialOutput})
.done(function (secondOutput) {
func(initialOutput, secondOutput);
});
});
}
chainPost("iwantdata.htm", "iwantmoredata.htm", 0, function (first, second) {
alert(first);
alert(second);
});
You can just nest them, starting the 2nd one in the completion function of the first and so on:
$.getSomeData = function() {
$.postJSON("iwantdata.htm",{data:data},function(data) {
$.postJSON("iwantmoredata.htm",{data:data},function(data)){
// use the data here
});
});
};
When dealing with asychronous functions, you cannot write code such as:
$.getSomeData();
$.useSomeData();
By definition, the first is asynchronous so it will not have completed yet with the second function is called and javascript does not have the ability to stop JS execution until an asynchronous operation is done.
You could pass your use function to the get function and then it would get called when the data was available as an addition to the above example like this:
$.getSomeData = function(fn) {
$.postJSON("iwantdata.htm",{data:data},function(data) {
$.postJSON("iwantmoredata.htm",{data:data},function(data)){
fn(data);
});
});
};
Then, you'd have a getSomeData(useFn) function that would take an argument of the function to call when all the data was ready.
Deferred objects [docs] are perfect for this. Unfortunately, your code example contains syntax errors and it is not clear how the calls are nested. So, I'm not sure if you want to run both Ajax calls after one another or parallel, but either way is possible.
Here are two examples. Have a look at the documentation for more information and play around with it.
Note: .postJSON is not a built in jQuery method, I assume here that you are returning the return value from the $.ajax (or $.post) function.
Parallel Ajax calls:
$.getSomeData = function() {
var a = $.postJSON("iwantdata.htm", {data:data});
var b = $.postJSON("iwantmoredata.htm", {data:data});
// return a new promise object which gets resolved when both calls are
// successful
return $.when(a, b);
};
// when both calls are successful, call `$.useSomeData`
// it will have access to the responses of both Ajax calls
$.getSomeData.done($.useSomeData);
See: $.when
Chained Ajax calls:
... where the response of the first call is the input for the second one. This is only an example, of course you can pass any data you want.
$.getSomeData = function() {
return $.postJSON("iwantdata.htm", {data:data}).pipe(function(response) {
// execute the second Ajax call upon successful completion
// of the first one
return $.postJSON("iwantmoredata.htm", {data:response});
});
};
// if both Ajax calls are successful, call `$.useSomeData`
// it will have access to the response of the second Ajax call
$.getSomeData.done($.useSomeData);
See: deferred.pipe()
If you have a more complex logic, you can also create, resolve or reject your own deferred objects. Have a look at the examples in the documentation.

Why is return not working in getJSON and why cant I write into variable from getJSON?

I have a function which uses getJSON but its not working like I expected.
function balbla(name, param) {
$.getJSON("/blabla.json?name=" + name + "&param=" + param, function(data) {
return data.bla;
});
}
When I use alert(data.bla) in the getJSON method it works but when I try return data.bla it doesnt. Also when I create a variable and try to write the value of data.bla to it it simply doesnt work!
// I tried this:
function getRouteData(name, param) {
return $.getJSON('/routes_js.json', {route:name, opt: param});
}
function getRoute(name, param) {
getRouteData(name, param).done(function(data) {
return data.route;
});
}
But when I call getRoute("bla", "blub") it still returns undefined.
AJAX is asynchronous. You cannot easily return a value in such a function that depends on the result of the AJAX call. Change your function to accept a callback:
function balbla(name, param, cb) {
$.getJSON('/blabla.json', {name:name, param: param}, function(data) {
cb(data.bla);
});
}
And use it like this:
balbla('foo', 'bar', function(bla) {
// do stuff
});
An even cleaner way would be returning the jqXHR object:
function balbla(name, param) {
return $.getJSON('/blabla.json', {name:name, param: param});
}
When calling it, use the deferred/promise interface of the jqXHR object to attach a success callback:
balbla('foo', 'bar').done(function(data) {
alert(data.bla);
});
Note that using $.ajax() in synchronous mode is not an option you should consider at all. It may hang the browser's UI (or at least the active tab) until the request finished. Besides that, asynchronous callbacks are the way everyone does it.
If you do not like using callback functions, you could use a preprocessor such as tamejs to generate the asynchronous functions automatically.
The function with your return statement:
function(data) {
return data.bla;
}
… is not being called by your code (it is being called deep inside jQuery), so you have no way to put an assignment of the left hand side of the function call.
It is also being called as part of an asynchronous function, so the balbla function will have finished running and returned before it the anonymous one is ever called.
If you want to do something with the response data, do it inside the anonymous callback function.
getJSON is asynchronous, not synchronous. You need to use a callback so your logic needs to be done in two steps. Calling step and the processing step.

How do "recursive AJAX callbacks" in JavaScript work?

I am using the Github API to retrieve data about one of my repos and I am running into trouble with callback functions and recursive functions overlapping (as in recursive functions with callbacks attached to them)
Here is the script on jsfiddle as well as below:
(function () {
'use strict';
function makeAJAXCall(hash, cb) {
$.ajaxSetup({
accept: 'application/vnd.github.raw',
dataType: 'jsonp'
});
$.ajax({
url: hash,
success: function (json) {
//console.info(json);
// Time for callback to be executed
if (cb) {
cb(json);
}
},
error: function (error) {
console.error(error);
// an error happened, check it out.
throw error;
}
});
}
function parseBlob(hash) {
return makeAJAXCall(hash, function (returnedJSON) { // no loop as only one entry
console.log(returnedJSON.data);
return returnedJSON.data.content;
});
}
function walkTree(hash) {
var tree = 'https://api.github.com/repos/myusername/SVG-Shapes/git/trees/' + hash;
return makeAJAXCall(tree, function (objectedJSON) {
var objectList = [], i, entry;
for (i = 0; i < objectedJSON.data.tree.length; i += 1) {
entry = objectedJSON.data.tree[i];
//console.debug(entry);
if (entry.type === 'blob') {
if (entry.path.slice(-4) === '.svg') { // we only want the svg images not the ignore file and README etc
//console.info(entry.path)
objectList.push(parseBlob(entry.url));
}
} else if (entry.type === 'tree') {
objectList.push(walkTree(entry.sha));
}
}
if (cb) {
console.log(objectList);
cb(objectList);
}
return objectList;
});
}
$(document).ready(function () {
var returnedObjects = walkTree('master', function (objects) { // master to start at the top and work our way down
console.info(objects);
});
});
}());
The JSON returned is either blog (file) or tree (directory). If it is a tree the walkTree function is called again. I do not understand how the callback will behave here as well as how to get the data it (should) return(s) out of the function and into the final block at the very bottom.
Can someone clarify how I should be doing this?
Ajax calls are usually asynchronous. That means that when you make the ajax call, it just initiates the ajax call and it finishes some time later. Meanwhile, the rest of your code after the initiation of the ajax call keeps running until completion.
Then, sometime later when the ajax call finishes, the success function is called and, in your case, the callback function gets called by the success function. It is important to understand that the success function is called much later after the makeAJAXCall() function has already finished.
Thus, you cannot return the ajax data from the makeAJAXCall() function because it isn't known yet when that function returns.
In fact, the only two places you can use the results of the ajax call are:
In the success handler directly
In some function that the success handler calls which in your case it the callback function.
So, it is doing you no good to return returnedJSON.data.content; from the callback function. That is just returning into some internal part of the ajax infrastructure and doing nothing. That return value will just be dropped on the floor and lost.
Instead, you need to put whatever code wants to use returnedJSON.data.content right there in that callback function (or pass it to another function with a function call).
Ajax is asynchronous. That means you can't do normal sequential programming when using ajax. Instead, you have to do event driven programming where the event in this case is the callback that is called upon a success completion of the ajax call. All work that uses those ajax results needs to commence from that success handler or the callback that is called from it.

Categories