I am working on Web page having an ajax call to the server and from the server(Controller) again a WCF service is called(which takes time) for fetching some data.
Inside server(Controller) i called to service in Parallel by using Task and async-await.
My problem is:
after opening the page that has code for calling the controller and WCF service, I can't redirect my tab/page to another URL by clicking on anchor tab present in UI. until ajax call result is retrieved.
UI CODE:
$(function () {
if (AutomationType.toLowerCase() === "desktop") {
$.ajax({
async: true,
url: "/" + AutomationType + "/Home/GetAllController",
data: { "hostName": hostname},
type: 'POST',
dataType: 'json'
}).success(function (response) {
debugger;
})
}
});
i have tried to abort the ajax call also as below,
$(function() {
$.xhrPool = [];
$.xhrPool.abortAll = function() {
$(this).each(function(i, jqXHR) { // cycle through list of recorded connection
jqXHR.abort(); // aborts connection
$.xhrPool.splice(i, 1); // removes from list by index
});
}
$.ajaxSetup({
beforeSend: function(jqXHR) { $.xhrPool.push(jqXHR); }, // annd connection to list
complete: function(jqXHR) {
var i = $.xhrPool.indexOf(jqXHR); // get index for current connection completed
if (i > -1) $.xhrPool.splice(i, 1); // removes from list by index
}
});
})
// Everything below this is only for the jsFiddle demo
$('a').click(function () {
$.xhrPool.abortAll();
});
Server(Controller) Code
public async Task<JsonResult> GetAllController(string hostName)
{
string IsControllerRunning = string.Empty;
var currentHost = string.Empty;
var currentRunId = string.Empty;
var currentStatus = string.Empty;
var ipDns = string.Empty;
Stopwatch sw = new Stopwatch(); sw.Start();
List<List<ExecutionStepResult>> returnresultArray = new List<List<ExecutionStepResult>>();
List<Task<IEnumerable<ExecutionStepResult>>> taskList = new List<Task<IEnumerable<ExecutionStepResult>>>();
Debug.WriteLine("starting 1 " + sw.Elapsed);
var resultArray = hostName.TrimEnd('^').Split('^');
for (int i = 0; i < resultArray.Length; i++)
{
string host = resultArray[i];
Task<IEnumerable<ExecutionStepResult>> task = new Task<IEnumerable<ExecutionStepResult>>(() => getServiceResultByTask(host));
task.Start();
taskList.Add(task);
}
foreach (Task<IEnumerable<ExecutionStepResult>> taskitem in taskList)
{
try
{
Debug.WriteLine("calling task " + sw.Elapsed);
IEnumerable<ExecutionStepResult> val = await taskitem;
returnresultArray.Add(val.ToList());
}
catch (Exception ex)
{
returnresultArray.Add(new List<ExecutionStepResult>() { new ExecutionStepResult() { IsError = true, ErrorMessage="true" ,CustomMessage = ex.Message.ToString() } });
}
}
for (int i = 0; i < resultArray.Length; i++)
{
string host = resultArray[i];
currentHost = host.Split('|').GetValue(1).ToString();
currentStatus = host.Split('|').GetValue(2).ToString();
currentRunId = host.Split('|').GetValue(0).ToString();
ipDns = host.Split('|').GetValue(3).ToString();
List<ExecutionStepResult> exeResponse = returnresultArray[i].ToList();
if (exeResponse.Count() > 0 && (currentStatus != "3" || (currentStatus == "3" && exeResponse[i].ErrorMessage == "true")))
IsControllerRunning += host + "|" + exeResponse[0].CustomMessage + "^";
else if (exeResponse.Count() > 0 && currentStatus == "3" && exeResponse[0].ErrorMessage == "false")
IsControllerRunning += host;
}
Debug.WriteLine("end " + sw.Elapsed);
sw.Stop();
return Json(IsControllerRunning, JsonRequestBehavior.AllowGet);
}
calling WCF service:
private IEnumerable getServiceResultByTask(string hosts)
{
using (var service = new RemoteCommandClient())
{
try
{
System.Threading.Thread.Sleep(15000);
string currentHost = hosts.Split('|').GetValue(1).ToString();
string currentStatus = hosts.Split('|').GetValue(2).ToString();
string currentRunId = hosts.Split('|').GetValue(0).ToString();
string ipDns = hosts.Split('|').GetValue(3).ToString();
IEnumerable<ExecutionStepResult> result = service.ExecuteRemoteWithRunId("CHECK_CURRENT_EXECUTION", Convert.ToInt32(currentRunId));
return result;
} catch (Exception ex)
{ throw ex; }
}
}
Still, I don't know how to open /redirect a page URL if an ajax call is running on the server. I am using signalR in the same page also. Please help.
I have this code fragment:
if(!encryption_state){
if(cKey=="" || cKey==null){
cKey=getKey(aid); //here we trying to obtain key
if(cKey!="" && cKey!=null && cKey!=undefined){
if(isJSON(jKey) && encryption_state){
var tjKey = JSON.parse(jKey);
tjKey[aid] = cKey;
jKey = JSON.stringify(tjKey);
}else{
jKey = json.stringify({aid: cKey});
}
encryption_state=true;
}
}
if(!encryption_state){
if(cKey=="" || cKey==null){
cKey=rndstr(32); //generate string
}
var arr = {};
if(isJSON(jKey)) arr = JSON.parse(jKey);
arr[aid] = cKey;
jKey = JSON.stringify(arr);
encryption_state = true;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
But when i call getKey(kaid) function:
function getKey(kaid){
$.ajax({
method: "POST",
url: "/?mod=key&fnc=syncKey",
data: {
aid: kaid
},
done: function(data) {
var tret = (JSON.parse(data)['msg']);
return tret;
}
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Browsers don't continue do function getKey(), they do next commands in parent function, i don't know why they ignore web server answer and don't let function return server response :(
in general, an ajax call is asynchronous. That means, a sequence like
var a = 0;
a = getAwithAjaxFromServer(...);
console.log(a);
will immediately print "0" while the ajax is still runnng.
Your entire logic with cleyand encryption_state has to be put into the done function:
if(!encryption_state){
if(cKey=="" || cKey==null){
cKey=getKey(aid);
}
}
and in your ajax:
function getKey(kaid){
$.ajax({
method: "POST",
url: "/?mod=key&fnc=syncKey",
data: {
aid: kaid
},
done: function(data) {
var tret = (JSON.parse(data)['msg']);
.... PUT ALL THE LOGIC HERE .....
}
});
}
You must understand asynchronous mechanism in javascript to continue calling ajax. There are a lot of resources and stackoverflow questions. For example: https://www.pluralsight.com/guides/front-end-javascript/introduction-to-asynchronous-javascript
So, you can convert the code so:
if(!encryption_state){
var serverKeyCallback = function(cKey) {
if(cKey!="" && cKey!=null && cKey!=undefined){
if(isJSON(jKey) && encryption_state){
var tjKey = JSON.parse(jKey);
tjKey[aid] = cKey;
jKey = JSON.stringify(tjKey);
}else{
jKey = json.stringify({aid: cKey});
}
encryption_state=true;
}
};
var localKeyCallback = function(cKey) {
if(!encryption_state){
if(cKey=="" || cKey==null){
cKey=rndstr(32); //generate string
}
var arr = {};
if(isJSON(jKey)) arr = JSON.parse(jKey);
arr[aid] = cKey;
jKey = JSON.stringify(arr);
encryption_state = true;
}
}
manageKey(cKey, aid, serverKeyCallback, localKeyCallback);
}
function manageKey(cKey, kaid, serverKeyCallback, localKeyCallback) {
if(cKey=="" || cKey==null) {
$.ajax({
method: "POST",
url: "/?mod=key&fnc=syncKey",
data: {
aid: kaid
},
done: function(data) {
var tret = (JSON.parse(data)['msg']);
serverKeyCallback(tret);
localKeyCallback(tret);
}
});
}
else {
localKeyCallback(cKey);
}
}
Defining two encapsulated pieces of code, one to execute after serverResponse, and the other to execute after the serverResponse or when you have the cKey locally stored. I haven't tested the code, but it must work as you expect.
I have a program which calls a function in javascript with 1 o more requests to 1 servlet, I want to execute request after request and get the response after each exucution, to make this I have 1 function, but it only shows the result after all requests have been executed.
function cmd(args) {
width = 0;
var res = args.split('\n');
var largo = res.length;
var progressLength = 100 / largo;
for (var i = 0; i < largo; i++)
{
if (res[i] == 'desconectar')
{
desconectar();
break;
}
else
{
executeCMD(res[i]);
}
}
}
function executeCMD(args)
{
$.ajax({
type: "POST",
url: 'Controlador',
data: {cmd: args, operacion: 1},
success: function (response) {
document.getElementById('respuesta').value = document.getElementById('respuesta').value + response;
},
dataType: 'text',
async: false
});
}
If I add window.alert(response); inside success field it shows the progress step by step and works fine, but it show alerts which I don't want.
This is I want http://imgur.com/a/9nclR but I'm getting only last picture.
The solution if anyone is intersting was using a recursive function as next:
function cmd(args) {
width = 0;
move(0);
var res = args.split('\n');
var largo = res.length;
var valInit = 0;
if (largo > valInit)
{
executeCMD(res, valInit);
}
}
function executeCMD(args, i)
{
$(document).ready(function () {
$.ajax({
type: "POST",
url: 'ControladorServlet',
data: {cmd: args[i], operacion: 1, ticket: ticket, iddispositivo: sesion},
success: function (response) {
var textarea = document.getElementById('respuesta');
var res = response.trim().split('\n');
if(error){//dc}
else
{
document.getElementById('respuesta').value = document.getElementById('respuesta').value + response.trim() + "\n\n";
var valor = (100) * (i + 1) / args.length;
move(valor);
if (i + 1 < args.length)
{
executeCMD(args, i + 1);
}
}
},
dataType: 'text'
});
});
}
This is what the code below does:
Goes to a table in a database and retrieves some search criteria I will send to Google API (the PHP file is getSearchSon.php)
After having the results, I want to loop around it, call the Google API (searchCriteriasFuc) and store the results in an array
The last part of the code is doing an update to two different tables with the results returned from Google API (updateSearchDb.php)
In my code, I am using setTimeout in a few occasions which I don't like. Instead of using setTimeout, I would like to properly use callback functions in a more efficient way (This might be the cause of my problem) What is the best way of me doing that?
$(document).ready(function() {
$.ajax({
url: 'getSearchSon.php',
type: 'POST',
async: true,
dataType: 'Text',
/*data: { }, */
error: function(a, b, c) { alert(a+b+c); }
}).done(function(data) {
if(data != "connection")
{
var dataSent = data.split("|");
var search_criterias = JSON.parse(dataSent[0]);
var date_length = dataSent[1];
var divison_factor = dataSent[2];
var length = search_criterias.length;
var arrXhr = [];
var totalResultsArr = [];
var helperFunc = function(arrayIndex)
{
return function()
{
var totalResults = 0;
if (arrXhr[arrayIndex].readyState === 4 && arrXhr[arrayIndex].status == 200)
{
totalResults = JSON.parse(arrXhr[arrayIndex].responseText).queries.nextPage[0].totalResults;
totalResultsArr.push(totalResults);
}
}
}
var searchCriteriasFuc = function getTotalResults(searchParam, callback)
{
var searchParamLength = searchParam.length;
var url = "";
for(var i=0;i<searchParamLength;i++)
{
url = "https://www.googleapis.com/customsearch/v1?q=" + searchParam[i] + "&cx=005894674626506192190:j1zrf-as6vg&key=AIzaSyCanPMUPsyt3mXQd2GOhMZgD4l472jcDNM&dateRestrict=" + date_length;
arrXhr[i] = new XMLHttpRequest();
arrXhr[i].open("GET", url, true);
arrXhr[i].send();
arrXhr[i].onreadystatechange = helperFunc(i);
}
setTimeout(function()
{
if (typeof callback == "function") callback.apply(totalResultsArr);
}, 4000);
return searchParam;
}
function callbackFunction()
{
var results_arr = this.sort();
var countResultsArr = JSON.stringify(results_arr);
$.ajax({
url: 'updateSearchDb.php',
type: 'POST',
async: true,
dataType: 'Text',
data: { 'countResultsArr': countResultsArr },
error: function(a, b, c) { alert(a+b+c); }
}).done(function(data) {
var resultsDiv = document.getElementById("search");
if(data == "NORECORD") resultsDiv.innerHTML = 'Updated failed. There was a problem with the database';
else resultsDiv.innerHTML = 'Update was successful';
}); //end second ajax call
}
//llamando funcion principal
var arrSearchCriterias = searchCriteriasFuc(search_criterias, callbackFunction);
}
else
{
alert("Problem with MySQL connection.");
}
}); // end ajax
});
How you did it in 2015
Callbacks are things of the past. Nowadays you represent result values of asynchronous tasks with Promises. Here is some untested code:
$(document).ready(function() {
$.ajax({
url: 'getSearchSon.php',
type: 'POST',
async: true,
dataType: 'text'
/*data: { }, */
}).then(function(data) {
if (data == 'connection') {
alert("Problem with MySQL connection.");
} else {
var dataSent = data.split("|");
var search_criterias = JSON.parse(dataSent[0]);
var date_length = dataSent[1];
var divison_factor = dataSent[2];
return Promise.all(search_criterias.map(function(criteria) {
return $.ajax({
url: "https://www.googleapis.com/customsearch/v1"
+ "?q=" + criteria
+ "&cx=005894674626506192190:j1zrf-as6vg"
+ "&key=AIzaSyCanPMUPsyt3mXQd2GOhMZgD4l472jcDNM"
+ "&dateRestrict=" + date_length,
type: 'GET'
});
})).then(function(totalResultsArr) {
totalResultsArr.sort();
var countResultsArr = JSON.stringify(totalResultsArr);
return $.ajax({
url: 'updateSearchDb.php',
type: 'POST',
async: true,
dataType: 'text',
data: { 'countResultsArr': countResultsArr },
error: function(a, b, c) { alert(a+b+c); }
});
}).then(function(data) {
var resultsDiv = document.getElementById("search");
if(data == "NORECORD") {
resultsDiv.innerHTML = 'Updated failed. There was a problem with the database';
} else {
resultsDiv.innerHTML = 'Update was successful';
}
});
}
}).then(null, function() {
alert('Some unexpected error occured: ' + e);
});
});
This is how you do it in 2016 (ES7)
You can just use async/await.
$(document).ready(async() => {
try {
var data = await $.ajax({
url: 'getSearchSon.php',
type: 'POST',
async: true,
dataType: 'text'
/*data: { }, */
});
if (data == 'connection') {
alert("Problem with MySQL connection.");
} else {
var dataSent = data.split("|");
var search_criterias = JSON.parse(dataSent[0]);
var date_length = dataSent[1];
var divison_factor = dataSent[2];
var totalResultsArr = await Promise.all(
search_criterias.map(criteria => $.ajax({
url: "https://www.googleapis.com/customsearch/v1"
+ "?q=" + criteria
+ "&cx=005894674626506192190:j1zrf-as6vg"
+ "&key=AIzaSyCanPMUPsyt3mXQd2GOhMZgD4l472jcDNM"
+ "&dateRestrict=" + date_length,
type: 'GET'
}))
);
totalResultsArr.sort();
var countResultsArr = JSON.stringify(totalResultsArr);
var data2 = await $.ajax({
url: 'updateSearchDb.php',
type: 'POST',
async: true,
dataType: 'text',
data: { 'countResultsArr': countResultsArr },
error: function(a, b, c) { alert(a+b+c); }
});
if(data2 == "NORECORD") {
resultsDiv.innerHTML = 'Updated failed. There was a problem with the database';
} else {
resultsDiv.innerHTML = 'Update was successful';
}
}
} catch(e) {
alert('Some unexpected error occured: ' + e);
}
});
UPDATE 2016
Unfortunately the async/await proposal didn't make it to the ES7 specification ultimately, so it is still non-standard.
You could reformat your getTotalResults function in the following matter, it would then search rather sequential, but it should also do the trick in returning your results with an extra callback.
'use strict';
function getTotalResults(searchParam, callback) {
var url = "https://www.googleapis.com/customsearch/v1?q={param}&cx=005894674626506192190:j1zrf-as6vg&key=AIzaSyCanPMUPsyt3mXQd2GOhMZgD4l472jcDNM&dateRestrict=" + (new Date()).getTime(),
i = 0,
len = searchParam.length,
results = [],
req, nextRequest = function() {
console.log('received results for "' + searchParam[i] + '"');
if (++i < len) {
completeRequest(url.replace('{param}', searchParam[i]), results, nextRequest);
} else {
callback(results);
}
};
completeRequest(url.replace('{param}', searchParam[0]), results, nextRequest);
}
function completeRequest(url, resultArr, completedCallback) {
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.onreadystatechange = function() {
if (this.readyState === 4 && this.status == 200) {
var totalResults = JSON.parse(this.responseText).queries.nextPage[0].totalResults;
resultArr.push(totalResults);
completedCallback();
}
};
req.send();
}
getTotalResults(['ford', 'volkswagen', 'citroen', 'renault', 'chrysler', 'dacia'], function(searchResults) {
console.log(searchResults.length + ' results found!', searchResults);
});
However, since you already use JQuery in your code, you could also construct all the requests, and then use the JQuery.when functionality, as explained in this question
Wait until all jQuery Ajax requests are done?
To get the callback execute after google calls are finished you could change:
var requestCounter = 0;
var helperFunc = function(arrayIndex)
{
return function()
{
if (arrXhr[arrayIndex].readyState === 4 && arrXhr[arrayIndex].status == 200)
{
requestCounter++;
totalResults = JSON.parse(arrXhr[arrayIndex].responseText).queries.nextPage[0].totalResults;
totalResultsArr.push(totalResults);
if (requestCounter === search_criterias.length) {
callbackFunction.apply(totalResultsArr);
}
}
}
}
then remove the setTimeout on searchCreteriaFuc.
Consider using promises and Promise.all to get all much cleaner :D
I am new to doing jQuery ajax calls and am trying to test an ajax call I have attempted to write today. Here it is.
var heartbeatInterval = 30000;
var heartBeatTimer = null;
var retryCount = 0;
var maxRetries = 10;
$().ready(function () {
var url = $.url("/pollBulletin.htm");
heartBeatTimer = setInterval(function () {
$.ajax({
url: url,
type: 'GET',
error: function (data) {
retryCount = retryCount + 1;
if (heartBeatTimer != null && retryCount >= maxRetries) {
clearInterval(heartBeatTimer);
}
},
success: function (bulletinBarMessage) {
retryCount = 0;
var respContent = "";
respContent += bulletinBarMessage.messageLevel + " : ";
respContent += bulletinBarMessage.message;
}
});
// When communication with the server is lost stop the heartbeat.
}, heartbeatInterval);
});
At the moment the code is never falling into the success part of the call. Can someone confirm if it looks ok? I'm not sure if I have coded this right. I know the server side code is doing the write thing. At the moment it is just return a null (server side).
Server side...
public BulletinBarMessage getBulletinBarMessage() {
JdbcTemplate select = this.getJdbcTemplate();
List<BulletinBarMessage> messages = select.query(BULLETIN_LOOKUP_SQL, new BulletinBarMessageRowMapper());
BulletinBarMessage bulletinBarMessage = null;
if (messages != null && !messages.isEmpty()){
bulletinBarMessage = (BulletinBarMessage)messages.get(0);
}
return bulletinBarMessage;
}