I am trying to check whether some email addresses are registered on a website or not with cURL function.
So in this case I have 3 textarea elements. The first contains lists of email, the second contains live email (indicated that email is registered) and the third contains unregistered email. Then there is button called "Check", if user clicks this then it makes an AJAX request, one after another, and shows result one after another, instead of multiple AJAX request in one time (async: true) or one by one AJAX request but one time result at the end of request (async: false).
The problem if I use async: true my browser will crash for big lists and if I use async: false I don't know whether my application is running or not since it shows the result at the end of request, even request is one after one.
Then so to make my question simple here is my code.
$("div#check").click(function(){
//Assume i just grab email lists from text area and put in array
var mail_lists_clean = ["a#yahoo.com", "b#aol.com", "c#gmail.com"];
var promises = [];
$.each(mail_lists_clean, function(index, value){
var promise = $.ajax({
method: "POST",
url: "valid_check.php",
//cache: false,
async: false,
data: {
email: value
}
}).success(function(data) {
if (data == "live") {
//append email to second textarea
}
else {
//append email to third textarea
}
});
promises.push(promise);
});
$.when.apply($, promises)done(function() {
alert("All Request done!");
}).fail(function() {
console.log("error");
});
});
Can anyone help me make AJAX requests one after another and show results one after another? Please correct my code above. Thanks.
To make ajax call one by one
you need to make recursion call at $.ajax success callback function.
function ProcessEmailList(mail_list) {
// process one email at a time
var value = mail_list.pop();
// if there is email in the array
if (value) {
$.ajax({
method: "POST",
url: "valid_check.php",
async: false,
data: {
email: value
}
}).done(function(data) {
if (data == "live") {
//append email to second textarea
} else {
//append email to third textarea
}
// recursion call, process rest of the email
ProcessEmailList(mail_list);
}).fail(function() {
console.log("error");
});
} else {
// no more email in the array, we have processed all
alert("All Request done!");
}
};
$("div#check").click(function() {
//Assume i just grab email lists from text area and put in array
var mail_lists_clean = ["a#yahoo.com", "b#aol.com", "c#gmail.com"];
ProcessEmailList(mail_lists_clean);
});
Why not pass All the emailadresses at once in a single ajax request separated by a certain character and pass the result back? That way long lists of addresses wont be a problem and it Will save You a lot of hassle of figuring out which request was handled and which one wasnt. It would Be better for performance as well.
Related
For example, say a page returns search results based on debounced user text.
How do you account for the case where an endpoint has a highly variable latency in which the second call can return before the first call.
E.g.
User is typing "books and movies" with a keyup debounce of 500ms
The user slightly pauses in the middle so the string is "books", this triggers a search call.
The user continues typing and finishes, triggering the second call with "books and movies".
The second call returns first, populating the list based on "books and movies".
Then the first call, which was delayed comes back and re-renders the list based on "books".
The user sees only "books" and is confused.
The surefire way to solve this is with a button to manually trigger the call. I'd like to avoid this though so I've increased the debounce but I'm wondering if there's a better way.
We suppose that you use jQuery to make ajax calls.
One solution is to use a pooling system: basically an array containing ajax requests.
Each time, a new request is emitted, you abort all request in the pool.
So you ensure that the last request made will be the only one that will end.
Here is the implementation of the pool:
jQuery.xhrPool = [];
jQuery.xhrPool.abortAll = function () {
jQuery(this).each(function (idx, jqXHR) {
jqXHR.abort();
});
jQuery.xhrPool.length = 0;
};
Here is an example on how to use it with the "search repository API" from GitHub (https://developer.github.com/v3/search/#search-repositories):
jQuery.xhrPool = [];
jQuery.xhrPool.abortAll = function () {
jQuery(this).each(function (idx, jqXHR) {
jqXHR.abort();
});
jQuery.xhrPool.length = 0;
};
$(document).ready(function(){
$("#SearchField").autocomplete({
source: function( request, response ) {
// First we abort all other request
jQuery.xhrPool.abortAll();
$.ajax({
url: "https://api.github.com/search/repositories",
method: "get",
dataType: "jsonp",
data: {
q: request.term
},
beforeSend: function (jqXHR) {
// Before sending the request we add it to the pool.
jQuery.xhrPool.push(jqXHR);
},
success: function(data) {
var items = new Array();
for(var i=0;i<data.data.items.length;i++)
{
items.push(data.data.items[i].name);
}
response(items);
}
});
},
minLength: 3,
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.css" >
<input type="text" id="SearchField" />
Javascript works synchronously so there is no possibility of race conditions if you write your code correctly.
I guess you are using ajax (ajax is supposed to be async, don't use sync ever, once you go sync, you can't go back) to get the query result. You are probably using some code like this:
var req=new XMLHttpRequest();
req.onreadystatechange=function(){
if (req.readyState==4){
if (req.status==200){
// Your callback here which shows autocomplete suggestions maybe?
}
}
}
Hold on to that req variable. So once you do a new request, you can simply discard the old request like:
req.onreadystatechange=null;
You can also abort the ajax request like:
req.abort();
I have the following array
var arrayOfResults = []; // Results after like statement
I make a call to the database which returns me a json result as shown here:
[{
"id": "{fcb42c9c-3617-4048-b2a0-2600775a4c34}",
"pid": "{34214CCB-90C3-4D75-958B-5A1D0FBDD971}",
"ttl": "Easter Bunny",
"img": "/~/media/Images/Recipes/Easter/Filled Pasta/LF_Baked-Spring-Vegetables-Ravioli_920.ashx?h=910\u0026w=910",
"url": "Some url",
"taggedwith": ["{3A54907D-4171-4F4E-8FE8-3A38DA1E874F}", "{6CD78C6B-F435-45EC-BE16-810E80311C23}", "{74528A6F-C40B-4030-A278-A4C9A2F46A47}", "{6DC82B78-61F6-45A0-A63C-EA590BB1057E}", "{E9EF1A41-51D0-403D-9373-37B7A880B251}"],
"articleddate": "2015-05-02",
"tname": "Recipe",
"rbrand": ["{1F6EDA5D-4681-40F0-B455-7C343AC25B72}"]
}, {
"id": "{2e4b04b6-334f-42e9-afd7-ddc4e08417ad}",
"pid": "{C611BAC8-E8E0-4693-920B-93BD5EE2386B}",
"ttl": "Latina Fettuccini \u0026 Summer Sauce with Prawns Recipe",
"img": "/~/media/Images/Recipes/Latina Fresh/Plain Pasta/LF_Fettuccini-Summer-Sauce-Prawns_920.ashx?h=910\u0026w=910",
"url": "Some url",
"taggedwith": ["{3A54907D-4171-4F4E-8FE8-3A38DA1E874F}", "{6CD78C6B-F435-45EC-BE16-810E80311C23}", "{74528A6F-C40B-4030-A278-A4C9A2F46A47}", "{6DC82B78-61F6-45A0-A63C-EA590BB1057E}", "{E9EF1A41-51D0-403D-9373-37B7A880B251}"],
"articleddate": "2015-05-02",
"tname": "Recipe",
"rbrand": ["{1F6EDA5D-4681-40F0-B455-7C343AC25B72}"]
}]
On the UI I have a text field, which the user can enter free text.
I call the following ajax method when the user has entered roughly 5 characters, what I'm trying to achieve is I want to perform a like statement on the ttl field within the above array, If the ttl field matches or is like the freeText the user has entered then I want to push that item in to the array 'arrayOfResuts' however I see the alert message found yet it doesn't push the item into the new array, I know this because I alert the length at the end of the ajax call and its 0;
var addItem = false;
var freeText = $('#searchKeywords').val();
$.ajax({
url: 'search?t=&s=DateDesc&type=globalsearch&q=',
type: 'GET',
dataType: 'json',
success: function (searchDataList) {
console.log(searchDataList)
for (var i = 0; i < searchDataList.length; i++) {
addItem = false;
if (freeText.length > 0) { // Filter on free text
if (searchDataList[i].ttl.indexOf(freeText) > -1) { // if title contains free text then we need to add it to the arrayOfResults[].
alert('found');
arrayOfResults.push(searchDataList[i]) // This doesn't seem to work.
addItem = true;
}
}
} // End of for loop
},
error: function (request, error) {
}
});
alert(arrayOfResults.length);
Now I'm not 100% sure what's actually going wrong, so any help would be appreciated.
Your alert is running before your AJAX request is complete.
Since the AJAX request is asyncronous the console.log() code runs before the success is called and so your not printing the result you want.
To print the results simply print within the success and error functions of the AJAX request. Doing so in the complete function will not help since it runs asyncronously from the others.
As the other answers mentioned you need to handle the data within the success block. You can do it directly like below, or for more complex cases call a new function to handle the data at the end of the success statement.
Update code:
var freeText = $('#searchKeywords').val();
$.ajax({
url: 'search?t=&s=DateDesc&type=globalsearch&q=',
type: 'GET',
dataType: 'json',
success: function (searchDataList) {
console.log(searchDataList);
for (var i = 0; i < searchDataList.length; i++) {
addItem = false;
if (freeText.length > 0) {
if (searchDataList[i].ttl.indexOf(freeText) > -1) {
alert('found');
arrayOfResults.push(searchDataList[i]);
addItem = true;
}
}
} // End of for loop
if (arrayOfResults.length > 1) {
alert(arrayOfResults.length);
console.log(arrayOfResults);
}
},
error: function (request, error) {
}
});
Your alert will always be 0 because AJAX is asynchronous (the A in AJAX stands for that) and you call your alert synchronously.
What happens is, the ajax request gets the data while the synchron code runs as usual. Now that the ajax request is done clearly after you call your alert it cannot log anything that makes sense.
If you want a function to be called when the asynchronous request is done, wheter it was successful or not, use done: additionally to success: and error:. This code will run when the request is done and show you the actual length.
I have an ajax request that gets called several times based on the number of request objects in an array. The order in which these objects are in inside of the array is important, and needs to be reflected in a dynamically generated list in that same order. When the server sends back each response I update a <ul> as shown below.
$.ajax({
type: 'POST',
url: baseServiceURL + 'report/',
processData: false,
dataType: 'json',
contentType: 'application/json',
data: payload,
crossDomain: true,
})
.done(function (response) {
updateUI(response);
})
.fail(function (jqXHR, textStatus) {
// handle failure
});
var updateUI = function (response) {
// Update the drop-down list
$('#dropdown').append('<li><a class="dd-option" data-value="' + response.ReportName + '" data-path="' + response.ReturnURL + '" href="#">' + response.ReportName + '</a></li>');
// do more stuf...
};
How can I dynamically build the list in such a way to where the response display in the proper order? One thing I have done is add a order param to the request who's value is the index of the request object in the array. My thought is my service can send that value back in the response so the javascript can act on it.
EDIT: The question here is asking basically the same thing except rather than using a getJSON command and appending divs I'm using a post and appending <li> elements.
There are two possible strategies here.
Update your UI immediately upon receiving response and then re-render if a new value is received
Wait until all ajax replies have finished and then render your UI
For (1) you should just keep a running total of all items
var $dropdown = $('#dropdown');
var renderDropdown = function(reports) {
//use lodash or underscore.js here cause implementing this manually is annoying
var sortedSelections = _.sortBy(reports, 'order');
var htmlPerItem = sortedSelections.map(function(item) {
return '<li><a ..... </li>';
});
$dropdown.html(htmlPerItem.join(''));
}
var reportSelections = [];
payloads.map(function(payload) {
$.ajax({ ... })
.then(function(response) {
reportSelections.push(response);
renderDropdown(reportSelections);
})
})
for (2) you can use jquery $.when
var gettingResults = payloads.map(function(payload) {
return $.ajax({ .... });
});
$.when(gettingResults).then(function() {
//the first arg will be response1, the second response2, etc
var reportSelections = _.sortBy(arguments, 'order');
renderDropdown(reportSelections);
});
Note in (1) you render once per item but get an updating view as items come in. In (2) you render only once but have to wait until all loading is complete.
Of course a variation of (1) is that you don't re-render anything, but merely insert items into the correct location as they are loaded. That's going to be more difficult to debug and more code so I leave it as an exercise for the reader (use jquery's $.fn.data to store the original item with the element).
I have simple autocomplete input field with Javascript like this:
$('#search').on('keyup', function () {
var query = $(this).val();
$.ajax({
type: "GET",
url: "/search",
data: { query: query }
}).done(function (results) {
showSearchResults(results);
});
});
Sometimes first call takes more time then second or third and results are overridden.
How can I make sure that results only from the latest successful call are displayed?
I mean if I got response from call #3 - I no longer care about calls #1 and #2 and don't want them to override results of call #3.
Ajax function is in default asynchronous it means that many of functions can run on same time. If You wrote 3 letters it will run 3 times, after 3 keyups. If you want to run function in sequence just add setting async: false.
$.ajax({
type: "GET",
url: "/search",
async: false,
data: { query: query }
}).done(function (results) {
showSearchResults(results);
});
But i think You should add some delay, so function will not run immediately after every keyup, just after last one.
I suggest that you bind an incremental id to each ajax request that you send. When you get a response, just check that it carries last given id.
let lastXHRid=0; // tracker of last sent ajax request
$('#search').on('keyup', function () {
let reqXHR = $.ajax({ // create a variable out of $.ajax returned value
type: "GET",
url: "/search",
data: { query: $(this).val() }
});
lastXHRid++; // increment the XHR counter
reqXHR.id = lastXHRid; // attach id to the request
reqXHR.done(function(results, status, respXHR) {
if ( respXHR.id == lastXHRid ){ // compare id of received and last sent requests
showSearchResults(results);
}
});
});
(Edit: I initially suggested tracking the unix timestamp of last sent request, but as #seth-battis suggested in the comments, a sequence number is far enough. As a bonus, I also debugged my sample snippet!)
I have a given collection of items to be processed; each item must wait for the completion of the previous one.
By collection of items I mean an array of integer values.
By "processing" I mean make a POST to a HTTP server, passing the integer value of each array element.
I've found something that looks like waht I'm looking for: doSynchronousLoop.js but I wonder if there are alternatives.
If your site may pause rendering while doing the requests, here's a solution with jQuery:
// process 5 items
for (var i = 0; i< 5; i++) {
// ajax request done with jquery
$.ajax({
async: false, /* this makes it execute synchronously */
url: "the url to handle item #i",
type: "POST",
success: function(msg) {
// process data for item #i
}
})
}
Edit: you can solve it asynchronously, too:
items = [put your items here]
current_item = 0
function processItem() {
if (current_item == items.length) {
// list processing finished
return;
}
$.ajax({
async: true,
url: "the url to handle item #current_item",
type: "POST",
success: function(msg) {
// process data for item #current_item
processItem();
current_item++;
}
})
}
Don't miss to put the variables in a scope, I just left them in global scope to make the example easier to understand.
See also the docs: jQuery.ajax