Ajax inside ajax in loop - javascript

I have the code (structure):
for (var x = 0; x < array1.length; x++){
(function(x) {
$.ajax({
url : "http://someurl1.ru/"+array1[x]+"/",
async: false,
success : function(someresult1){
array2.length = 0;
array3.length = 0;
var br = someresult1.split('<br>');
for (var b = 0; b < br.length-1; b++){
var space = br[b].split(" ");
array2.push(space[0]);
array3.push(space[1]);
}
for (var v = 0; v < array2.length; v++){
(function(v) {
$.ajax({
url : "http://someurl2.ru/"+array2[v]+"_"+array3[v]+"/",
async: false,
success : function(someresult2){
if(JSON.stringify(someresult2).search(some_array[x]) != -1){
$.ajax({
url : "http://someurl3.ru/"+array2[v]+"/"+array3[v]+"/"+some_another_array[x]+"",
async: false,
success : function(someresult3){
array4.push(someresult3);
}
});
}
}
});
})(v);
}
}
});
})(x);
}
I need to activate async in my request because it freezes my page and slowing down work of the program. There some explanation about program work:
1. Take first element of array1.
2. Creating link and sending request.
3. Taking result and doing some stuff with it.
4. Creating link and sending request.
5. Taking result and doing some stuff with it.
6. Creating link and sending request.
7. Taking result.
8. AND ONLY NOW we take second element of array1 and doing the same.
I need of synchronuous/continuous ajax requests (with "wait" result) in loop.

I just restructured the way you request URLs and the kind of callback. Alert me if something isn't right. Although, I didn't change the program actions and style. I'm really lazy to make that better.
Instead of loops I made a function to go consuming each array1 item, for example, and the same with the array2. When one request is done in one of these arrays, the next request starts if existent, else do nothing in array1 and when in array2 it just callbacks to the array1 to do the next array item request with the consume function.
var len = array1.length; // Memorize array1 length
function consume(i) {
var xhr = new XMLHttpRequest(); // Request
xhr.open("GET", "http://someurl1.ru/" + array1[i] + "/" , true);
xhr.onreadystatechange = function() {
if(this.readyState === 4) {
// Status 200 is success
if(this.status === 200) {
// `this` invokes the `xhr` object
// Your success block is here
successCallback(i, this.responseText);
// Consume next array1 items if length isn't ranged
}else{
// Error block is here; can be 403, 404, 500+, ... etc.
}
}
}
xhr.send()
}
consume(0);
function consume2(i, array2, array3, arrayLen, callback) {
var xhr = new XMLHttpRequest(); // Request
xhr.open("GET", "http://someurl2.ru/" + array2[i] + "_" + array3[i] + "/", true);
xhr.onreadystatechange = function() {
if(this.readyState === 4) {
// Status 200 is success
if(this.status === 200) {
// Your success block is here
if(JSON.stringify(xhr.responseText).search(some_array[i]) !== -1){
var xhr2 = new XMLHttpRequest(); // Request
xhr2.open("GET", "http://someurl3.ru/" + array2[i] + "/" + array3[i] + "/" + some_another_array[i], true);
xhr2.onreadystatechange = function() {
if(this.readyState === 4) {
// Status 200 is success
if(this.status === 200) {
// Your success block is here
array4.push(xhr2.responseText);
// Consume next array2 items
if(i < len)
consume2(++ i)
;else
callback()
}else{
// Error block is here; can be 403, 404, 500+, ... etc.
}
}
};
xhr2.send()
}
}else{
// Error block is here; can be 403, 404, 500+, ... etc.
}
}
}
xhr.send()
}
function successCallback(f, data) {
array2.length = 0;
array3.length = 0;
var br = someresult1.split('<br>');
for (var b = 0; b < br.length; b++){
var space = br[b].split(" ");
array2.push(space[0]);
array3.push(space[1]);
}
consume2(0, array2, array3, array2.length, function() {
if(f < len)
consume(++ f)
})
}
I'll update this code yet, but I don't understand what you surely want to do with it.

Related

Images after javascript are showed with a delay and reordering

I get the src code for image from PHP and after show at the HTML but the images are shown with a delay. How can I show the images all together without reordering after all loaded?
HTML
<div id="keys"></div>
JS
function sendGETDataToServer() {
// Set up our HTTP request
var xhr = new XMLHttpRequest();
// Setup our listener to process completed requests
xhr.onreadystatechange = function () {
// Only run if the request is complete
if (xhr.readyState !== 4) return;
// Process our return data
if (xhr.status >= 200 && xhr.status < 300) {
var JsonResponse = xhr.responseText;
var response = JSON.parse(JsonResponse);
console.log(response);
if (response[0] == "200 OK") {
var i;
for (i = 0; i < response[1]; i++) {
let img = document.createElement("img");
img.src = response[2 + i].FilePath;
img.setAttribute("style", "width:8%; padding-left:1em; float:left");
$("#keys").append(img);
}
}
} else {
console.log("error", xhr);
}
};
xhr.open("GET", "load.php");
xhr.send();
}
Your code should look like something like that
if (response[0] == '200 OK') {
var i;
var nbLoaded = 0;
var nbToLoad = 0;
var pendingImages = [];
for (i = 0; i < response[1]; i++) {
nbToLoad++;
let img = document.createElement('img');
img.src = response[2 + i].FilePath;
img.setAttribute('style', 'width:8%; padding-left:1em; float:left');
img.onload = () => {
nbLoaded++;
if (nbLoaded === nbToLoad) {
pendingImages.forEach((image) => {
$('#keys').append(image);
});
}
};
pendingImages.push(img);
}
}
The short answer to your problem: There isn't really one. There is not a way to know what order your images will arrive in, and you certainly cannot control the delay. What you can control is the order you show them in. The simplest way to do this is to wait until you have received all of your images, and while you are receiveing them, you store them in an array somewhere. After you receive the final image, you could simply order the array the way you want your images to be displayed, and run through it to actually put the images on the page. If you need any help with the specifics, please feel free to ask!

Making multiple asynchroonus requests and getting their return value

As in the title, I'm wondering how to send few asynchronous requests and, after they're processed, change a part of my website (in this instance a single counter). Doing it synchronous way gives just the outcome I expect to get, but it freezes the website for a quite a long time. My current code is as follows:
var twitchReq = new XMLHttpRequest;
function twitchR(x,y)
{
var api_key = "some_api_key";
var source = "https://api.twitch.tv/kraken/streams/" + y + "?&client_id=" + api_key + "&callback=";
x.open("GET", source, false);
x.send(null);
var z = twitchPR();
return z;
}
function twitchPR()
{
if(twitchReq.status == 200)
{
if(twitchReq.readyState == 4)
{
var a = twitchReq.responseText;
var b = JSON.parse(a);
var c = twitchD(b);
return c;
}
}
}
function twitchD(x)
{
if(x.stream == null)
{
console.log("Offline");
return 1;
}
else
{
console.log(x);
return 2;
}
}
function twitchWidget()
{
var t = [
"Nervarien",
"Jankos",
"LolVander",
"RossBoomsocks",
"ESL_LOL",
"Xayoo_",
"Kubon_"
]
var j=0;
var n=0;
for(i=0;i<7;i++)
{
if(twitchR(twitchReq,t[i]) == 1)
{
j=j+1;
}
else
{
n=n+1;
}
}
document.getElementById("test-1").innerHTML = "Online: " + n + "<br>" + "Offline: " + j;
}
I've figured out that the nail in the coffin of this solution is waiting for one request to be finished before sending another, not to mention freezing any other code in queue. So: how do i process the outcome of my request once they are finished and wait for the others to be finished at the same time?
EDIT: Regarding 'possible duplicate' mark - I've seen that thread and yet, I couldn't tell how to solve my problem. The difference is, he could just use ajax promises, while I had no idea how to make one, and therefore couldn't use solutions posted there.
There are several ways to do it. I will suggest here to use a promise for the HTTP request:
// Helper function to make Http request and return a promise
function promiseHttpData(source) {
return new Promise(function (resolve, reject) {
var req = new XMLHttpRequest;
req.onload = resolve.bind(null, req);
req.onerror = reject.bind(null, req);
req.open("GET", source);
req.send();
});
}
function twitchR(y) {
var api_key = "some_api_key";
var source = "https://api.twitch.tv/kraken/streams/" + y
+ "?&client_id=" + api_key + "&callback=";
return promiseHttpData(source).then(twitchPR);
}
function twitchPR(twitchReq) {
var a = twitchReq.responseText;
var b = JSON.parse(a);
var c = twitchD(b);
return c;
}
function twitchD(x) {
if(x.stream == null) {
console.log("Offline");
return 0; // Use of zero is easier to work with
} else {
console.log(x);
return 1;
}
}
function twitchWidget() {
var t = [
"Nervarien",
"Jankos",
"LolVander",
"RossBoomsocks",
"ESL_LOL",
"Xayoo_",
"Kubon_"
]
var promises = t.map(twitchR); //Launch request for each
// Get the promised values for all promises:
Promise.all(promises).then(function (values) {
var n = values.filter(Number).length; // returns the number of non-zeroes.
var j = t.length - n;
document.getElementById("test-1").innerHTML =
"Online: " + n + "<br>" + "Offline: " + j;
});
}
I think you need http://caolan.github.io/async/ lib, They have a very good set of methods to accomplish parallel and series Ajax calls. Adding one lib for a single method is kind of quite expensive, but this way code is more organized and easy to maintain.

Storing the value of variable in JS

Since my main language is C, I am used to pointers and I love them. Now I have some project which I need to finish in Javascript and I've got a problem which I don't know how to solve.
I want to store the value of a variable which I got from GET request. I have a script to send GET to PHP page, which then sends GET to my daemon written in C. When I get the string I wanted, I use length to measure the size of the string I got and in next GET request I want to send that number of bytes I got as the URL parameter.
window.onload = function() {
if (bytes === undefined) {
var bytes = 0;
}
var url = "/test/log.php?q=" + bytes;
function httpGet(url) {
var xhttp = new XMLHttpRequest();
xhttp.open("GET", url, true);
xhttp.onload = function(e) {
if (xhttp.readyState === 4) {
if (xhttp.status === 200) {
console.log(xhttp.responseText);
var option = "";
obj = JSON.parse(xhttp.responseText);
for (var key in obj) {
option += obj[key];
}
document.getElementById("list").innerHTML = asdf;
bytes = option.length;
}
};
xhttp.onerror = function(e) {
console.error(xhttp.statusText);
}
};
xhttp.send();
}
var updateInterval = 2000;
function update() {
httpGet(url);
setTimeout(update, updateInterval);
}
update();
}
So, the focus is on the variable bytes. It should have the value 0 when the script is a first time called, and after every loop (it loops every 2 seconds, I didn't show the loop in the code) it should have the value of the previous length of received string.
You just need to make sure to add the bytes param onto your url in a way that changes with each call rather than just once at page load when it will always be 0.
window.onload = function() {
if (bytes === undefined) {
var bytes = 0;
}
var url = "/test/log.php?q=";
function httpGet(url) {
var xhttp = new XMLHttpRequest();
xhttp.open("GET", url, true);
xhttp.onload = function(e) {
if (xhttp.readyState === 4) {
if (xhttp.status === 200) {
console.log(xhttp.responseText);
var option = "";
obj = JSON.parse(xhttp.responseText);
for (var key in obj) {
option += obj[key];
}
document.getElementById("list").innerHTML = asdf;
bytes = option.length;
}
};
xhttp.onerror = function(e) {
console.error(xhttp.statusText);
}
};
xhttp.send();
}
var updateInterval = 2000;
function update() {
httpGet(url + bytes);
setTimeout(update, updateInterval);
}
update();
}
Instead of a fixed value of url make it to a function and it will give you always the current Url with the modified version of bytes, if you modify it
You have only to change this parts
var url = ...
// to
function getUrl() {
return "/test/log.php?q=" + bytes;
}
...
// and
xhttp.open("GET", url, true);
// to
xhttp.open("GET", getUrl(), true);
I'd declare the variable in a context that doesn't empty its value when the function is called. So, you can declare your variable "bytes" before the function, and then looping through that function. In this case, the variable will hold the last value until you overwrite it.
That should work!

Chrome Extension: Data is not being inserted nor fetched

I am using WebSQL. I am trying to add data in Async Block which is making data not to be inserted. Code is given below:
function fetchData(){
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://localhost/x/fetch.php", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// JSON.parse does not evaluate the attacker's scripts.
var resp = xhr.responseText;
if(resp != null) {
var json = JSON.parse(resp)
console.log(resp);
var data = json['data'];
if(data != null) {
openDatabase('documents', '1.0', 'documents', 5*1024*1024, function (db) {
alert('Called'); // This is called after below two calls.
insertRecord(db);
fetchRecord(db);
});
//var dbConnection = openDbConnect();
//createTable(dbConnection);
for(var a=0;a <= data.length;a++) {
alert(data[a].title);
}
}
}
}
}
xhr.send();
}
JSON Dump
{"data":[{"id":"1","title":"- Parts I & II”,”CODE”:”xxx”,”product_url":"http:\/\/www.example.com","image_url":"http:\/\/ecx.images-example.com\/images\/I\/61ujIIMyW7L.jpg","price":"$25.00"},{"id":"2","title”:”AJDJDDJDr”,”Code”:”XX”,”product_url":"http:\/\/www.example.com","image_url":"http:\/\/dc.images-example.com\/images\/I\/41jFVZL72YL.jpg","price":"$10.99"}]}
Try this ;)
Problem in this loop condition:
for(var a = 0; a <= data.length; a++) {
^
Here you are starting from 0 and looping to data.length
So to loop with arrays as array index starts from 0 loop till a <= data.length - 1 OR a < data.length
for(var a = 0; a < data.length; a++) {
OR
for(var a=0; a <= (data.length - 1); a++) {
Instead of for loop you can use for...in like this:
for(var index in data){
alert(data[index].title);
}

Intermittent behavior in my AJAX, Greasemonkey script

I've a small Greasemonkey script that doesn't include any random part, but its results change with each page reload.
I'm a noob and I'm probably doing something wrong, but I don't know what. I hope you'll be able to help me.
The code is too large and too poorly written to be reproduced here, so I'll try to sum up my situation:
I have a list of links which have href=javascript:void(0) and onclick=f(link_id).
f(x) makes an XML HTTP request to the server, and returns the link address.
My script is meant to precompute f(x) and change the href value when the page loads.
I have a function wait() that waits for the page to load, then a function findLinks() that gets the nodes that are to be changed (with xpath).
Then a function sendRequest() that sends the xhr to the server. And, finally handleRequest() that asynchronously (r.onreadystatechange) retrieves the response, and sets the nodes previously found.
Do you see anything wrong with this idea?
Using a network analyzer, I can see that the request is always sent fine, and the response also.
Sometimes the href value is changed, but sometimes for some links it isn't and remains javascript:void(0).
I really don't see why it works only half the time...
function getUrlParameterFromString(urlString, name) {
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(urlString);
if (results == null) {
return "";
} else {
return results[1];
}
}
function getUrlParameter(name) {
return getUrlParameterFromString(window.location.href, name);
}
function wait() {
var findPattern = "//a";
var resultLinks = document.evaluate(findPattern, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
if (resultLinks == null || resultLinks.snapshotLength == 0) {
return setTimeout(_wait, 100);
} else {
for (var i = 0, len = resultLinks.snapshotLength; i < len; i++) {
var node = resultLinks.snapshotItem(i);
var s = node.getAttribute('onclick');
var linkId = s.substring(2, s.length - 1); // f(x)->x
sendRequest(linkId, node);
}
}
}
function sendRequest(linkId, nodeToModify) {
window.XMLHttpRequest ? r = new XMLHttpRequest : window.ActiveXObject && (r = new ActiveXObject("Microsoft.XMLHTTP"));
if (r) {
r.open("POST", "some_url", !0);
r.onreadystatechange = function () {
handleRequest(nodeToModify, linkId, r);
}
r.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
r.send(linkId);
}
}
function handleRequest(nodeToModify, num, r) {
if (r.readyState == 4) {
if (r.status == 200) {
console.log('handleRequest() used');
var a = r.responseText;
if (a == null || a.length < 10) {
sendRequest(num, nodeToModify);
} else {
var url = unescape((getUrlParameterFromString(a, "url")).replace(/\+/g, " "));
nodeToModify.setAttribute('href', url);
nodeToModify.setAttribute('onclick', "");
}
} else {
alert("An error occurred: " + r.statusText)
}
}
}
wait();
It looks like that script will change exactly 1 link. Look-up "closures"; this loop:
for (var i = 0, len = resultLinks.snapshotLength; i < len; i++) {
var node = resultLinks.snapshotItem(i);
var s = node.getAttribute('onclick');
var linkId = s.substring(2, s.length - 1); // f(x)->x
sendRequest(linkId, node);
}
needs a closure so that sendRequest() gets the correct values. Otherwise, only the last link will be modified.
Try:
for (var i = 0, len = resultLinks.snapshotLength; i < len; i++) {
var node = resultLinks.snapshotItem(i);
var s = node.getAttribute('onclick');
var linkId = s.substring(2, s.length - 1); // f(x)->x
//-- Create a closure so that sendRequest gets the correct values.
( function (linkId, node) {
sendRequest (linkId, node);
}
)(linkId, node);
}

Categories

Resources