Several setTimeout() functions [duplicate] - javascript

I'm trying to send emails with a 10 seconds delay between. I wrote this code:
$(document).ready(function() {
for (i = 0; i < 20; i++) {
setTimeout("SendEmail(" + i + ")", 5000);
}
});
function SendEmail(id) {
$.get("mimesender.php?id=" + id, function(data) {
var toAppend = "<span> " + data + "</span>"
$("#sentTo").append(toAppend);
});
}
server side code(php) gets the id and selects the email with the specified id from the database
$query="select email from clienti where id =".$id;
then sends the email, and sends back the current email
echo email;
However, something is wrong here. It seems like the the js function waits for 5 seconds, and then displays all the 20 email addresses at once.
Can you tell me what I'm doing wrong ? any "sleep "workaround will be greatly appreciated :)

Use interval instead of loop.
Working demo: http://jsfiddle.net/xfVa9/2/
$(document).ready(function() {
var tmr;
var i=0;
tmr=setInterval(function(){
if(i<20){
SendEmail(i);
alert("Sent "+i)
i++;
}else{
clearInterval(tmr);
}
},5000)
});

You should create a function which calls itself after 5 seconds
var i=0;
function sendEmailNow() {
SendEmail(i);
++i;
if(i<20) {
setTimeout(sendEmailNow, 5000);
}
}

What happens is that you call setTimeout 20 times, just after one another, with a timeout of 5 seconds. So naturally, all emails gets sent at once. You could change the loop to look like this:
for (i=0;i<20;i++) {
setTimeout("SendEmail("+ i + ")",(i+1)*5000);
}
There's alot of other options though, and they'd depend on just what suits your specific problem best.

First, pass a function to setTimeout.
Secondly, you'd be better off if you set the timeout for the next one in the queue after the current one is finished.
In the for loop:
sendEmail(0); // start sending first
and in the callback:
, function(data) {
if(id < 19) { // if next should be sent
setTimeout(function() {
SendEmail(id + 1);
}, 5000);
}
var toAppend = "<span> " + data + "</span>"
$("#sentTo").append(toAppend);
}

Your loop is setting up 20 timers to wait 5 seconds, then letting them all go at once.
Try something like this:
var email_count = 20;
var sendMails = function(){
SendEmail(email_count--);
if(email_count > 0){
setTimeout(sendMails, 5000);
}
}
setTimeout(sendMails, 5000)

Avoid jQuery. Learn JavaScript.
var i = 0; (otherwise leak into outer scope or runtime error)
Extra closure:
window.setTimeout(
(function (j) {
return function () {
sendEmail(j);
};
}(i)),
i * 10000);
sendEmail (code style: not a constructor)
You really want to escape $id in the server-side code to prevent SQL injection.

Related

Variable scope or return issue (not sure which)

Using the script below I'm attempting to create an object called temptagarray which gets populated with all the tags on a Tumblr weblog and their frequency. So it should end up looking like this:
{'performance': 10, 'installation': 5}
I know the object is being created and it looks correct (I can print it out in each loop) but I can't figure out how to use it after/outside the function i.e. at the bottom of the script where I attempt to document.write() it out. Is this a global/local variable issue, a return issue or do I need to address it in some way?
<script type="text/javascript">
var temptagarray = {};
var tags;
var tag;
function loadPosts () {
var key = "api_key=9I4rZAYQCbU1o5TSMZuyrlvXiQsNxKBicCJxNK5OKZ6G9pgdim";
var api = "https://api.tumblr.com/v2/blog/garrettlynch.tumblr.com/";
var retrieve_more = function (offset) {
$.getJSON(api + "posts?callback=?&filter=image&limit=20&offset=" + offset + "&" + key,function(data) {
//for each item (post) in the response
$.each(data.response.posts, function(i, item) {
//pull out the posts tags
tags = item['tags'];
//loop through the tags
for (i = 0; i < tags.length; i++)
{
tag = tags[i];
//if the tag already exists in the tag array
if (temptagarray[tag])
{
temptagarray[tag] = temptagarray[tag] + 1;
}
else
{
temptagarray[tag] = 1;
}
}
});
if (data.response.posts.length == 20) {
retrieve_more(offset + 20);
}
});
};
retrieve_more(0);
}
loadPosts();
document.write(JSON.stringify(temptagarray));
</script>
Thanks in advance
Garrett
Replace this:
if (data.response.posts.length == 20) {
retrieve_more(offset + 20);
}
...with this:
if (data.response.posts.length == 20) {
retrieve_more(offset + 20);
} else {
document.write(JSON.stringify(temptagarray));
}
The problem you're having is that, despite your document.write(...) command being located below the ajax call in your code, the ajax call is asynchronous and thus the callback will be invoked asynchronously as well. Basically, document.write(...) is being invoked long before you've had a chance to interact with the temptagarray variable in the ajax callback.
First things first - AJAX is Async Asynchronous.
So the code block does not wait for the previous instruction to be completed before it executes the next line.
So your document.writeline would have already been executed by the time the response comes back.
Try printing that info in the success call back after the if block and you would indeed see the response.
thanks for the replies. Below is what I have now as a workable solution as the result is going to call another function anyway. Reading a little bit more I'm wondering if I should be using a callback - is it better?
<script type="text/javascript">
//load posts from a Tumblr weblog
function loadPosts () {
//api key and weblog address
var key = "api_key=9I4rZAYQCbU1o5TSMZuyrlvXiQsNxKBicCJxNK5OKZ6G9pgdim";
var api = "https://api.tumblr.com/v2/blog/garrettlynch.tumblr.com/";
//tags object
var temptagarray = {};
//all tags and each tag
var tags;
var tag;
//looping function to keep retrieving posts until all are retrieved
var retrieve_more = function (offset) {
$.getJSON(api + "posts?callback=?&filter=image&limit=20&offset=" + offset + "&" + key,function(data) {
//for each item (post) in the response
$.each(data.response.posts, function(i, item) {
//pull out the posts tags
tags = item['tags'];
//loop through the tags
for (i = 0; i < tags.length; i++)
{
//pull out each tag
tag = tags[i];
//if the tag already exists in the tag array
if (temptagarray[tag])
{
//add 1 to its count
temptagarray[tag] = temptagarray[tag] + 1;
}
else
{
//set its count to 1
temptagarray[tag] = 1;
}
}
//to test object as it gets added to
//$("#Posts ul").append('<li>' + JSON.stringify(item, ['tags']) + '</li>')
});
//if the number of posts is more than 20
if (data.response.posts.length == 20)
{
//retrieve the next 20
retrieve_more(offset + 20);
}
else
{
//call the show result function
showresult(temptagarray);
}
});
};
//stop retrieving posts
retrieve_more(0);
}
loadPosts();
function showresult(tagarray)
{
$("#Posts ul").append('<li>' + JSON.stringify(tagarray) + '</li>');
//document.write(JSON.stringify(tagarray));
}
</script>

How to break CasperJS' repeat function when a condition is fulfilled?

I want to know if i can break a casper.repeat loop.
I have this script which does this..:
Searches google for agent 001, agent 002, agent 003, agent 004, agent 005, agent 006..... ....'til agent 011.
I want it to stop looping after it finds the text "James Bond".
Now it finds it, prints it out, but i dont know if and how to stop the casper.repeat loop.
var casper = require("casper").create({
clientScript: ["jquery.min.js"],
verbose: true,
logLevel: "info"
});
var mouse = require("mouse").create(casper);
var x = require('casper').selectXPath;
var webPage = require('webpage');
var page = webPage.create();
casper.on("remote.message", function(msg){
this.echo("remote> " + msg);
var test = msg;
if( test.indexOf('James Bond') >= 0){
casper.echo("Am Gasit James Bond");
}
});
casper.userAgent('Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36')
casper.start("https://www.google.com/ncr", function() {
this.echo("\nINCEPUTUL INCEPUTULUI TITLUL PAGINII IN START (LINIA DE MAI JOS)\n"+this.getTitle()+"\n");
}).viewport(1366,768);
casper.options.waitTimeout = 30000;
var variabila_mea = "agent ";
var numTimes = 11, count = 1;
casper.repeat(numTimes, function() {
if (count < 10) {
var i = "00"+count;
casper.waitForSelector(x('//*[#id="gbqfq"]'), function(){
this.evaluate(function(count, variabila_mea, i, numar) {
document.getElementsByClassName('gbqfif')[0].value=variabila_mea+i;
document.forms[0].submit();
nextPage(count);
}, ++count,variabila_mea , i,"00000");
console.log(variabila_mea);
casper.waitForSelector(x('//*[#id="gbqfq"]'), function(){
var inputValue = casper.evaluate(function () {
console.log("\n\n\n"+document.getElementsByClassName('rc')[0].outerHTML+"\n\n\n");
});
});
casper.wait(1000, function(){
console.log("\n_____________________");
casper.capture('aa'+i+'.png');
console.log("_____________________\n");
});
});
} else if (count < 100 && count > 9) {
var i = "0"+count;
casper.waitForSelector(x('//*[#id="gbqfq"]'), function(){
this.evaluate(function(count, variabila_mea, i, numar) {
document.getElementsByClassName('gbqfif')[0].value=variabila_mea+i;
document.forms[0].submit();
nextPage(count);
}, ++count,variabila_mea , i,"00000");
console.log(variabila_mea);
casper.waitForSelector(x('//*[#id="gbqfq"]'), function(){
var inputValue = casper.evaluate(function () {
console.log("\n\n\n"+document.getElementsByClassName('rc')[0].outerHTML+"\n\n\n");
});
});
casper.wait(1000, function(){
console.log("\n_____________________");
casper.capture('aa'+i+'.png');
console.log("_____________________\n");
});
});
} else {
var i = count;
casper.waitForSelector(x('//*[#id="gbqfq"]'), function(){
this.evaluate(function(count, variabila_mea, i, numar) {
document.getElementsByClassName('gbqfif')[0].value=variabila_mea+i;
document.forms[0].submit();
nextPage(count);
}, ++count,variabila_mea , i,"00000");
console.log(variabila_mea);
casper.waitForSelector(x('//*[#id="gbqfq"]'), function(){
var inputValue = casper.evaluate(function () {
console.log("\n\n\n"+document.getElementsByClassName('rc')[0].outerHTML+"\n\n\n");
});
});
casper.wait(1000, function(){
console.log("\n_____________________");
casper.capture('aa'+i+'.png');
console.log("\n_____________________");
});
});
}
});
casper.run();
The repeat loop is finished before the navigation has even begun. repeat is executed immediately by unrolling all the iterations into a queue before the execution is even triggered through casper.run. You cannot break a repeat loop when synchronous code is used and you certainly cannot break a repeat loop when steps are actually scheduled. But you can still achieve what you want to achieve by using recursion.
You need to define your looping body as a function and make it tail recursive.
function loopBody(index, numTimes){
if (conditionFailed || index >= numTimes) {
return;
}
this.then(function(){
// do something useful
});
this.then(function(){
loopBody.call(this, index+1, numTimes);
});
}
casper.start(url).then(function(){
loopBody.call(this, 0, numTimes);
}).run();
In your case a global variable is probably needed to track what is found in each "loop" iteration.
You should understand the working of casper.repeat();
Internal structure of repeat is below. Taken from git hub
/**
* Repeats a step a given number of times.
* #param Number times Number of times to repeat step
* #aram function then The step closure
* #return Casper
* #see Casper#then
*/
Casper.prototype.repeat = function repeat(times, then) {
"use strict";
for (var i = 0; i < times; i++) {
this.then(then);
}
return this;
};
From this you can see that once repeat is called ie repeat (numTimes,your function).
You can consider "then" parameter as what ever the function you are passing to repeat. So once the call is happened it will work inside a for loop. So Breaking the Repeat after the call is not possible. Use Casper.byPassIf Casper.byPassUnless inside your function which you are passing to the repeat in order to bypass the execution.
Using this you an skip the steps inside your function. Which means repeat will stop only after reaching it end count. But it won't perform any steps because you are bypassing those with above mentioned functions. Further explanation of bypass function not comes under this scope of question. Actually it is work around you can try. Hope it will be helpful. If needed further clarification please feel free to ask. Enjoy !!!
Example the below loop will execute 10 times but only print 1 to 5.
var i=1;
loopcount=10
casper.repeat(loopCount, function() {
casper.thenBypassIf(function() {
return i >5;
}, 1);
casper.then(function() {
this.echo (i);
});
casper.then(function() {
i++;
});
});
How about this?
casper.keep_looping = true;
casper.repeat(some_counter, function() {
if (casper.keep_looping)
{
if (i_no_longer_want_to_loop) {
casper.keep_looping = false;
}
}
});
Since there is no way to break the casper.repeat loop (at least I haven't found it in the docs), then maybe avoiding the execution of the in-loop code is enough. The code above will run the loop until the "some_counter" is exhausted but the code in the loop will not be executed if you set the "i_no_longer_want_to_loop" variable to true.

setTimeout/Interval called from within $.each method?

I am a little confused, I have read from other places that timeout/interval is the best way to make a function in Javascript run every x seconds. I have to make it so that my function runs every 1 second, as this is a rule for the API I'm using.
My code is as follows:
$.each(match_details_json.result.players, function(index, v){
if (v.account_id == 38440257){ //finds desired playerid
var match_id_2 = matches[i];
hero = v.hero_id;
playerpos = v.player_slot;
var kills = v.kills;
var deaths = v.deaths;
var assists = v.assists;
var kda = ""+kills+"/"+deaths+"/"+assists+"";
console.log(match_id_2, hero, playerpos, result, gamemode, kda);
callback();
console.log(match_id_2, hero, result, gamemode, kda);
h=h+1;
setTimeout(get_match_details(h), 10000);
i=i+1;
}
else{
console.log('Not desired player, skipping...');
}
});
Lots of messy code there. But the important part is setTimeout(get_match_details(h), 10000);
Whether that is correct or not, that's me trying to say "Run this function again in 10 seconds" and to continue that, until the each method is finished. It doesn't work.
If necessary, here is my get_match_details function:
function get_match_details(){
$.ajax({
url: 'php/ApiMatchPull.php',
data: {accountid:'38440257', querytype:'GetMatchDetails', querycondition1:'match_id='+matches[h]},
success: function (data) {
console.log ('Match Details were was pulled successfully');
match_details_json = data;
matchdetailsfill(checkvalidity);
}
});
}
Thank you in advance.
This is precisely what setInterval & clearInterval are for.
So instead of setTimeout, you could use it something like :
var timer = setInterval(function() {
get_match_details(h);
}, 1000); // for every second
And when you want to stop it, use:
clearInterval(timer);
You execute the function get_match_details immedatiately, change your code to
setTimeout( function() {
get_match_details(h)
}, 10000 );
What happens in your code is that you loop through all your players and after 10 seconds as many Ajax calls (get_match_details) will be made at the same time.
If you want to have 10 seconds intervals between each ajax call you have to refactor your approach to something like this:
var l = [1,2,3,4,5];
var c = l.length;
var ix = -1;
ajax = function( n ) {
alert( 'do some ajax with ' + n )
}
call = function() {
if( c > ++ix ) {
ajax( l[ ix ] );
setTimeout( function() { call(); }, 1000 );
}
}
call();

Javascript - Images not cycling/rotating

I'm working on a script to rotate/cycle through images in javascript while respecting a limit on the amount of times it cycles through the images. What I have is below:
<a id="imageurl"><img id="Rotating1" border="0"></img></a>
<script language="JavaScript">
var delay = 3000; //6000 = change to next image after 6 seconds
var cycles = 2;
var currentCycle = 0;
function RotateImages(Start, delay)
{
var a = new Array("frown.gif","grim.gif","smile.gif", "bomb.gif");
var c = new Array("url1", "url2", "url3", "url4");
var b = document.getElementById('Rotating1');
var d = document.getElementById('imageurl');
var totalCycles = cycles * a.length;
// alert ("currentCycle: " + currentCycle);
// alert ("totalCycles: " + totalCycles);
if (Start>=a.length)
Start=0;
b.src = a[Start];
d.href = c[Start];
if (currentCycle < totalCycles) {
window.setTimeout("RotateImages(" + (Start+1) + ")", delay);
currentCycle++;
}
}
RotateImages(0, delay);
</script>
The script acts like it's working when I uncomment the alert boxes. When I comment them out, the rotation seems to stop. Any ideas on what is really going on and how to fix it?
Thanks!
perhaps you would like to change this line:
window.setTimeout("RotateImages(" + (Start+1) + ")", delay);
into:
window.setTimeout("RotateImages(" + (Start+1) + ", " + delay + ")", delay);
so that the next time RotateImages is called, it will keep the delay.
One fundamental issue to take into consideration is with setTimeout. The first parameter can be a reference to a function, whether it be an actual reference or a string reference, but you cant pass parameters along with it.
To do what you want, you need to pass a anonymous function to setTimeout. Also, Riyono is right that you should also pass the delay
setTimeout(function(){ RotateImages(Start++, delay) }, delay);
As far as your alert issue, I don't know what to tell you. But I know that the above will correct some issues.

This javascript setTimeout interacts with ajax requests in a really weird way

I'm writing this script so that it displays the status of an import script. It's supposed to call a function, that runs a http request, every X seconds.
function progres_import() {
//if(import_status != 'finalizat') {
alert("progres_import");
setTimeout(function() { return update_progres_import(); }, 2000);
setTimeout(function() { return update_progres_import(); }, 4000);
setTimeout(function() { return update_progres_import(); }, 6000);
setTimeout(function() { return update_progres_import(); }, 8000);
//setTimeout(function() { progres_import(); }, 400);
//}
//else {
//}
}
this is what i used to test the functionality. I put the comments in too just to show what I intend to ultimately do with it. I tried all the possible setTimeout calls, with quotes, without quotes, with and without the anonymous function.
var xmlhttp_import_progres;
function update_progres_import() {
xmlhttp_import_progres=GetXMLHttpObject();
if (xmlhttp_import_progres==null) {
alert ("Browser does not support HTTP Request (xmlhttp_import_progres)");
return;
}
var url="crm/ferestre/import_progres.php";
url=url+"?sid="+Math.random();
xmlhttp_import_progres.onreadystatechange=function() {
if (xmlhttp_import_progres.readyState == 4) {
progres_resp = xmlhttp_import_progres.responseText;
progres = progres_resp.split('_');
import_nrc = progres[0];
import_nrt = progres[1];
import_status = progres[2];
mesaj = 'Progres import: ' + import_nrc + ' / ' + import_nrt;
//document.getElementById("corp_import_mesaj").innerHTML = mesaj;
alert(progres_resp);
}
};
xmlhttp_import_progres.open("POST",url,true);
xmlhttp_import_progres.send(null);
}
this is the business end of the progres_import function.
what happens is i get the alert("progress_import") in the first function right as the import process starts, but the alert(progres_resp) in the second one starts popping up only after the import process is over (it still maintains the 2 second interval so in that sense the setTimeouts worked).
the php script in the ajax request just takes some session variables that the import script sets and prints them for the javascript to use (x imports of y total, z failed, stuff like this)
Any idea why it behaves like this?
xmlhttp_import_progres.readyState == 4) is only true at the end of the request. Hence, your alert dialogs pop up after finishing the request.
Furthermore, you can't expect your function to show alerts after a 2 second interval, because the server may or may not respond as fast.
A final note: If you want to have a periodical update function, use setInterval(function(){...}, 2000).
EDIT
Also, add var in this way: var xmlhttp_import_progres = GetXMLHttpObject();. Currently, you're globally defining the HTTP object, causing only one instance of the HTTP object to be accessible.
Here, can you try to edit just a little:
Please consider the above answer, but this code will make clear for you:
function progres_import() {
//if(import_status != 'finalizat') {
alert("progres_import");
setTimeout(function() { return update_progres_import(0); }, 2000);
setTimeout(function() { return update_progres_import(1); }, 4000);
setTimeout(function() { return update_progres_import(2); }, 6000);
setTimeout(function() { return update_progres_import(3); }, 8000);
//setTimeout(function() { progres_import(); }, 400);
//}
//else {
//}
}
AND
var xmlhttp_import_progres = [];
function update_progres_import(i) {
xmlhttp_import_progres[i]= GetXMLHttpObject();
if (xmlhttp_import_progres[i]==null) {
alert ("Browser does not support HTTP Request (xmlhttp_import_progres)");
return;
}
var url="crm/ferestre/import_progres.php";
url=url+"?sid="+Math.random();
xmlhttp_import_progres[i].onreadystatechange=function() {
if (xmlhttp_import_progres[i].readyState == 4) {
progres_resp = xmlhttp_import_progres[i].responseText;
progres = progres_resp.split('_');
import_nrc = progres[0];
import_nrt = progres[1];
import_status = progres[2];
mesaj = 'Progres import: ' + import_nrc + ' / ' + import_nrt;
//document.getElementById("corp_import_mesaj").innerHTML = mesaj;
alert(progres_resp);
}
};
xmlhttp_import_progres[i].open("POST",url,true);
xmlhttp_import_progres[i].send(null);
}

Categories

Resources