I have the following JS methods:
var foo = function() {
var dfd = $.Deferred();
console.log('foo');
dfd.resolve();
return dfd.promise();
};
var ajaxCall1 = function () {
var dfd = $.Deferred();
$.ajax({
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
url: 'xxxxxxx',
data: { },
success: function(response) {
dfd.resolve();
}
});
return dfd.promise();
};
var ajaxCall2 = function () {
var dfd = $.Deferred();
$.ajax({
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
url: 'xxxxxxx',
data: {},
success: function (response) {
dfd.resolve();
}
});
return dfd.promise();
};
var ajaxCall3 = function () {
var dfd = $.Deferred();
$.ajax({
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
url: 'xxxxxxx',
data: {},
success: function (response) {
dfd.resolve();
}
});
return dfd.promise();
};
and I am calling them via this code:
foo().done(function () {
return ajaxCall1();
}).done(function () {
return ajaxCall2();
}).done(function () {
return ajaxCall3();
});
The issue is that ajaxCall2 is called before the success of ajaxcall1 has occurred. Can you help me fixing this? I need to make ajax calls one by one when success of previous one has occurred.
Use the $.when
var deferredObject = $.ajax({});
$.when(deferredObject)
.then(function(){
var deferredobject2 = $.ajax({});
$.when(deferredobject2)
.then(function(){ alert('after 2nd ajax call');});
});
First of all, you can return the results of the $.ajax calls directly since they are promises already (no need for an intermediate Deferred):
var ajaxCall1 = function () {
return $.ajax({
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
url: 'xxxxxxx',
data: { }
});
};
var ajaxCall2 = function () {
return $.ajax({
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
url: 'xxxxxxx',
data: {}
});
};
var ajaxCall3 = function () {
return $.ajax({
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
url: 'xxxxxxx',
data: {}
});
};
Second, what you wanna use is .pipe() to effectively chain the calls:
foo().pipe(function () {
return ajaxCall1();
}).pipe(function () {
return ajaxCall2();
}).pipe(function () {
return ajaxCall3();
}).done(function() {
// call1, call2 and call3 done in sequence
}).fail(function() {
// one of the ajax requests failed
});
Simplify.
function foo() {
var dfd = $.Deferred();
console.log('foo');
dfd.resolve();
return dfd.promise();
}
function ajaxCall1() {
return $.ajax({
type: 'POST',
dataType: 'json',
url: 'xxxxxxx',
data: { },
success: function(response) {
console.log('ajaxCall1 success');
}
});
return dfd.promise();
}
// and so on for ajaxCall2 and ajaxCall3
Enhance.
foo().done(function () {
ajaxCall1().done(function () {
ajaxCall2().done(function () {
ajaxCall3();
});
});
});
http://jsfiddle.net/mattball/LxjDS/
Further reading:
How to chain ajax calls using jquery
jQuery Deferred not calling the resolve/done callbacks in order
jQuery deferred - do I need pipes or chains to achieve this pattern?
Same as the other answer except simplifying the callbacks with Frame.js
var responses = [];
for(var i=0; i<1000; i++){
Frame(function(callback){
$.ajax('myserver.api', {
data:i,
type:'post',
complete:function(response) {
responses.push(response);
callback();
}
});
});
}
Frame.start();
Normally, slamming the browser with AJAX requests like this would cause the browser to hang, and the response variables would be returned in the order they are received, rather than the original order they were sent in. Adding Frame to the mix here sorts all that out.
Or you could just use it to flatten out the callbacks:
Frame(function(next){
foo().done(next);
});
Frame(function(next){
ajaxCall1().done(next);
});
Frame(function(next){
ajaxCall2().done(next);
});
Frame(function(next){
ajaxCall3().done(next);
});
Frame(function(next){
//do more stuff
next();
});
Frame.start();
I've had similar problems working heavily with SharePoint web services - you often need to pull data from multiple sources before you're able to continue working.
To solve it I embedded this kind of functionality into my AJAX abstraction library. You can easily define a request which will trigger a set of handlers when complete. However each request can be defined with multiple http calls. Here's the component:
DPAJAX at DepressedPress.com
This very simple example creates one request with three calls and then passes that information, in the call order, to a single handler:
// The handler function
function AddUp(Nums) { alert(Nums[1] + Nums[2] + Nums[3]) };
// Create the pool
myPool = DP_AJAX.createPool();
// Create the request
myRequest = DP_AJAX.createRequest(AddUp);
// Add the calls to the request
myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [5,10]);
myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [4,6]);
myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [7,13]);
// Add the request to the pool
myPool.addRequest(myRequest);
Note that unlike many of the other solutions provided this method does not force single threading of the calls being made - each will still run as quickly as the environment allows but the handler will only be called when all are complete. The component also supports user-defined numbers of requests so you can force single-threading easily if you like. It also supports the setting of timeout values and retry attempts if your service is a little flakey.
I've found it insanely useful (and incredibly simple to understand) for this kind of work.
Related
I Have a 2 JavaScript functions what call one after another. like following.
updateUI(event);
syncCall();
function updateUI(event) {
formSubmitBtn = $(event.target).find('[type=submit]:not(".disabled")');
formSubmitBtn.attr('disabled', 'disabled');
var loadingText = I18n.t('Submitting');
formSubmitBtn.val(loadingText).text(loadingText);
}
function syncCall(){
$.ajax({
async: false,
dataType: 'json',
type: 'GET',
url: '/calls/synccall',
success: function (json) {
userIsSignedIn = json.is_signed_in;
}
});
}
I am updating a UI element before sync ajax call. but UI changes are not showing. When I try to debug the code it works fine.
I can imagine your code is doing something like
var userIsSignedIn;
updateUI(event);
syncCall();
nextThing(userIsSignedIn);
anotherThing();
moreThings();
With a simple change to syncCall - called asyncCall to be not confusing
function asyncCall(cb){
$.ajax({
dataType: 'json',
type: 'GET',
url: '/calls/synccall',
success: function (json) {
cb(json.is_signed_in);
}
});
}
your code re-written:
updateUI(event);
asyncCall(function(userIsSignedIn) {
nextThing(userIsSignedIn);
anotherThing();
moreThings();
});
Note the lack of var userIsSignedIn; required
Really a small change for improved end user experience
a second alternative is to wrap all the code you presented in a function tagged async
async function doThings() {
updateUI(event);
let userIsSignedIn = await ajaxCall(); // see below
nextThing(userIsSignedIn);
anotherThing();
moreThings();
}
and return a Promise from ajaxCall (what was syncCall)
function ajaxCall(){
return $.ajax({
dataType: 'json',
type: 'GET',
url: '/calls/synccall'
}).then(json => json.is_signed_in);
}
Run this through a transpiler (like babel) to produce code that should work on Internet Exploder and similarly "backward" browsers
Summary: In the end you have two choices
Use async:false and have rubbish user experience
embrace asynchrony and write code that befits the 21st century
Call this function beforeSend like as follows
function syncCall(){
$.ajax({
async: false,
dataType: 'json',
type: 'GET',
url: '/calls/synccall',
beforeSend:function(){
updateUI(event);// Call here
}
success: function (json) {
userIsSignedIn = json.is_signed_in;
}
});
}
If above not work try following
updateUI(event);
function updateUI(event) {
formSubmitBtn = $(event.target).find('[type=submit]:not(".disabled")');
formSubmitBtn.attr('disabled', 'disabled');
var loadingText = I18n.t('Submitting');
formSubmitBtn.val(loadingText).text(loadingText);
syncCall();// Try calling here
}
function syncCall(){
$.ajax({
async: false,
dataType: 'json',
type: 'GET',
url: '/calls/synccall',
success: function (json) {
userIsSignedIn = json.is_signed_in;
}
});
}
i have button that when you click on it
it run ajax that send id to controller
now controller do something and its ok no error in server side,,
but in the action in controller i have code with restsharp that
send request to rest web service its work fine too(),
but this part() is in foreach and run for 5 or ... time
and when i do this things sometime ajax takes to long and the error part of ajax code is run
what should i do ?
ajax code:
$(document).on("click", "#btn-submit", function () {
$.ajax({
type: 'POST',
url: '/Panel/CheckRefOrderCode',
data: JSON.stringify({
factorrefid: $("#ref-check").val()
}),
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (result) {
if (result.DntSuccess) {
} else {
}
},
error: function () {
}
});
});
action code
foreach(string s in str)
{
var client = new RestClient("http://**.com/api/v1/orders/status?support_code=71GD4A");
var request = new RestRequest(Method.POST);
request.AddHeader("token", "15befa43");
IRestResponse response = client.Execute(request);
RefOrderJsonViewModel.RefOrderJson reforderbackJson =
JsonConvert.DeserializeObject<RefOrderJsonViewModel.RefOrderJson>(response.Content);
if (reforderbackJson.status.ToLower() == "ok")
{
performed += reforderbackJson.data.performed;
order_status += reforderbackJson.data.order_status + "^";
}
}
and i add this to web.config
<httpRuntime executionTimeout="100000000" maxRequestLength="262144" />
Add a timeout to the ajax call:
$(document).on("click", "#btn-submit", function () {
$.ajax({
type: 'POST',
url: '/Panel/CheckRefOrderCode',
data: JSON.stringify({
factorrefid: $("#ref-check").val()
}),
contentType: 'application/json; charset=utf-8',
dataType: 'json',
**timeout: 10000 // sets timeout to 10 seconds**
success: function (result) {
if (result.DntSuccess) {
} else {
}
},
error: function () {
}
});
});
Check out this post on how to handle timeout error.
the problem still is on;
but i use this
Parallel.ForEach(myEnumerable, obj =>
{
// ...
});
instead regular
foreach
and do the body of foreach in parallel,
and the time is decreasing,
the problem solved
I am trying to execute a WCF service call, from function one(). Only once this is complete I want function two() to be executed. The issue I have is that function two() is invoked before function one() completes execution and the WCF service returns the result. How can I solve this please? I am using callback function, so I can't figure out why, given that the response does not exceed 3 seconds.
<script type="text/javascript">
var jsonGetFileResult = "";
function one(callback) {
setTimeout(function() {
//var jsonGetFileResult = "";
console.log('01: into one');
$.ajax({
type: 'GET',
url: ‘http: //wcf.google.com’, //this is the wcf call
contentType: "application/json; charset=utf-8",
dataType: 'json',
data: {},
timeout: 10000,
success: function(data) {
jsonGetFileResult = stringifyNewsletter(data);
console.log('03: ' + jsonGetFileResult);
},
error: function(data) {
alert(error);
}
});
callback();
}, 3000);
}
function stringifyNewsletter(data) {
var removeHeader = JSON.stringify(data);
var file = removeHeader.split('"');
console.log('02: ' + file[3]);
return file[3];
}
function two(linkToNewsletter) {
window.open(linkToNewsletter, '_blank', 'location=yes');
return false;
}
/* now we make use of the callback */
one(function() {
alert(jsonGetFileResult);
// "one" triggers "two" as soon as it is done, note how "two" is a parameter
two(jsonGetFileResult);
});
</script>
You're invoking the callback outside of the ajax "success" function. The $.ajax() call is asynchronous — the call will return to your code essentially immediately, after launching the HTTP request and without waiting for it to finish.
If you move the line
callback();
to inside the "success" handler, then that will run after the HTTP request completes.
You need to put callback inside success function like that:
function one(callback) {
setTimeout(function() {
//var jsonGetFileResult = "";
console.log('01: into one');
$.ajax({
type: 'GET',
url: ‘http: //wcf.google.com’, //this is the wcf call
contentType: "application/json; charset=utf-8",
dataType: 'json',
data: {},
timeout: 10000,
success: function(data) {
jsonGetFileResult = stringifyNewsletter(data);
console.log('03: ' + jsonGetFileResult);
callback();
},
error: function(data) {
alert(error);
}
});
}, 3000);
}
I have a AJAX request like this:
$.ajax({
type: 'GET',
url: url,
dataType: "json",
success: function(data) {
// ...
callbak(true);
},
})
.then(
function( response ) {
// ...
});
I'd like to run that callback function and so exit from that ajax request in success function and prevent deferred.then() execution.
In my case the callback is fired but after that deferred.then() is also executed and I don't want this to happen.
Any idea?
Thanks
Use a flag like so:
var executeThen = true;
$.ajax({
type: 'GET',
url: url,
dataType: "json",
success: function(data) {
// ...
executeThen = false;
callbak(true);
},
})
.then(function(response) {
if(executeThen){
// ...
}
});
I'm trying to get my function to return the data it got into another function but it doesn't seem to work? How can I get it to return the data?
function playerid(playername) {
$.ajax({
type: "POST",
url: "fn.php?playerid",
data: "playername="+playername,
success: function(data) {
//$("#test").text(data);
return data;
}
});
}
I want to use it in another function like this
showBids(playerid(ui.item.value));
function showBids(playerid) {
$.ajax({
type: "POST",
url: "poll.php?",
async: true,
dataType: 'json',
timeout: 50000,
data: "playerid="+playerid,
success: function(data) {
//.each(data, function(k ,v) {
//})
//$("#current_high").append(data);
setTimeout("getData()", 1000);
}
});
First of all, your playerid() does not return anything, so what do you want to use? It has only $.ajax() call in it, no return statement (one of the callbacks in $.ajax() has return statement, but see below).
Secondly, JavaScript does some things asynchonously, otherwise every interface element would need to wait to react to user action until the AJAX call returns from the server.
Use event-based approach, by passing callbacks to some functions. Then, after they finish, just call the callbacks passing them the result:
function getplayerid(playername, callback) {
$.ajax({
type: "POST",
url: "fn.php?playerid",
data: "playername="+playername,
success: function(data) {
//$("#test").text(data);
callback(data);
}
});
}
and then use it like that:
getplayerid(ui.item.value, showBids);
(notice function name change since it does not actually return player ID, it gets it and passes it to callback)
You could try to use syncronous Ajax:
function playerid(playername) {
return $.ajax({
type: "POST",
url: "fn.php?playerid",
data: "playername="+playername,
async : false //making Ajax syncronous
}).responseText;
}
Otherwise you need to use showBids function as callback:
function playerid(playername, callback) {
$.ajax({
type: "POST",
url: "fn.php?playerid",
data: "playername="+playername,
success: function(data) {
callback(data);
}
});
}
//Usage
playerid(ui.item.value,showBids);