I am trying to create a countdown with JQuery. I have different times in an array. When the first time ist finished, the countdown should count to the next time in the array.
I try to do this with the JQuery countdown plugin:
var date = "2017/04/25";
var time = ["13:30:49", "14:30:49", "16:30:49", "17:30:49"];
var i = 0;
while (i < time.length) {
var goal = date + " " + time[i];
$("#countdown")
.countdown(goal, function(event) {
if (event.elapsed) {
i++;
} else {
$(this).text(
event.strftime('%H:%M:%S')
);
}
});
}
This does not work... But how can i do this?
You should never use a busy wait especially not in the browser.
Try something like this:
var date = "2017/04/25";
var time = ["13:30:49", "14:30:49", "16:30:49", "17:30:49"];
var i = 0;
var $counter = $("#countdown");
function countdown() {
var goal = date + " " + time[i];
$counter.countdown(goal, function(event) {
if (event.elapsed) {
i++;
if (i < time.length) {
countdown();
}
} else {
$(this).text(
event.strftime('%H:%M:%S')
);
}
});
}
You can't use while or for loop in this case, because the operation you want to perform is not synchronous.
You could do for example something like this with the helper (anonynous) function:
var date = "2017/04/25";
var time = ["13:30:49", "14:30:49", "16:30:49", "17:30:49"];
var i = 0;
(function countdown(i) {
if (i === time.length) return;
var goal = date + " " + time[i];
$("#countdown")
.countdown(goal, function(event) {
if (event.elapsed) {
countdown(i++);
} else {
$(this).text(event.strftime('%H:%M:%S'));
}
});
})(0)
You need to restart the countdown when the previous one finishes, at the minute you're starting them all at the same time.
var date = "2017/04/25";
var time = ["13:30:49", "14:30:49", "16:30:49", "17:30:49"];
function startCountdown(i) {
if(i >= i.length) {
return;
}
var goal = date + " " + time[i];
$("#countdown")
.countdown(goal, function(event) {
if (event.elapsed) {
startCountdown(i++);
} else {
$(this).text(
event.strftime('%H:%M:%S')
);
}
});
}
startCountdown(0);
Related
How do I make A and B run in parallel?
async function runAsync(funcName)
{
console.log(' Start=' + funcName.name);
funcName();
console.log(' End===' + funcName.name)
};
function A()
{
var nowDateTime = Date.now();
var i = 0;
while( Date.now() < nowDateTime + 1000)
i++;
console.log(' A i= ' + i) ;
}
function B()
{
var nowDateTime = Date.now();
var i = 0;
while( Date.now() < nowDateTime + 1000)
i++;
console.log(' B i= ' + i) ;
}
runAsync(A);
runAsync(B);
The console shows that A starts first and B starts after A:
Start=A
A i= 6515045
End===A
Start=B
B i= 6678877
End===B
Note:
I am trying to use async for Chrome/Firefox, and keep the JS code compatible with IE11.
This C# code generates the proxy function runAsync:
if (isEI())
Current.Response.Write(" function runAsync(funcName){ setImmediate(funcName); }; ");
else
Current.Response.Write(" async function runAsync(funcName){ funcName(); } ");
https://jsfiddle.net/NickU/n2huzfxj/28/
Update.
My goal was to parse information and prepare (indexing and adding triggers) for an immediate response after user input. While the user is viewing the information, the background function has 3-10 seconds to execute, and the background function should not block UI and mouse and keyboard responses. Here is the solution for all browsers, including IE11.
Created a new Plugin to simulate parallel execution of funcRun during idle times.
Example of an original code:
$("input[name$='xxx'],...").each( function(){runForThis(this)}, ticksToRun );
The updated code using the Plugin:
$(document).zParallel({
name: "Example",
selectorToRun: "input[name$='xxx'],...",
funcRun: runForThis
});
Plugin.
(function ($)
{
// Plugin zParallel
function zParallel(options)
{
var self = this;
self.defaults = {
selectorToRun: null,
funcRun: null,
afterEnd: null,
lengthToRun: 0,
iterScheduled: 0,
ticksToRun: 50,
showDebugInfo: true
};
self.opts = $.extend({}, self.defaults, options);
}
zParallel.prototype = {
init: function ()
{
var self = this;
var selector = $(self.opts.selectorToRun);
self.lengthToRun = selector.length;
if (self.lengthToRun > 0)
{
self.arrayOfThis = new Array;
selector.each(function ()
{
self.arrayOfThis.push(this);
});
self.arrayOfThis.reverse();
self.opts.iterScheduled = 0;
self.whenStarted = Date.now();
self.run();
return true;
}
else
{
this.out('zParallel: selector is empty');
return false;
}
},
run: function ()
{
var self = this;
var nextTicks = Date.now() + self.opts.ticksToRun;
var _debug = self.opts.showDebugInfo;
if (self.opts.iterScheduled === 0)
{
nextTicks -= (self.opts.ticksToRun + 1); // Goto to Scheduling run
}
var count = 0;
var comOut = "";
while ((self.lengthToRun = self.arrayOfThis.length) > 0)
{
var curTicks = Date.now();
if (_debug)
{
comOut = self.opts.name + " |" + (curTicks - self.whenStarted)/1000 + "s| ";
if (self.opts.iterScheduled === 0)
this.out("START " + comOut + " remaining #" + self.lengthToRun);
}
if (curTicks > nextTicks)
{
self.opts.iterScheduled++;
if ('requestIdleCallback' in window)
{
if (_debug)
this.out(comOut + "requestIdleCallback , remaining #" + self.lengthToRun + " executed: #" + count);
window.requestIdleCallback(function () { self.run() }, { timeout: 1000 });
} else
{
if (_debug)
this.out(comOut + "setTimeout, remaining #" + self.lengthToRun + " executed: #" + count);
setTimeout(function (self) { self.run()}, 10, self);
}
return true;
}
var nexThis = self.arrayOfThis.pop();
self.opts.funcRun(nexThis);
count++;
}
if (self.opts.afterEnd!== null)
self.opts.afterEnd();
if (_debug)
this.out("END " + comOut + " executed: #" + count);
return true;
},
out: function (str)
{
if (typeof console !== 'undefined')
console.log(str);
}
};
$.fn.zParallel = function (options)
{
var rev = new zParallel(options);
rev.init();
};
})(jQuery);
// Examples.
(function ($)
{
var tab1 = $('#tbl1');
for (i = 0; i < 1000; i++)
$("<tr>"+
"<td>#" + i + "</td>"+
"<td><input id='a_" + i + "' value='" + i + "' >"+
"</td><td><input id='b_" + i + "' value='" + i + "' ></td></tr>")
.appendTo(tab1);
$(document).zParallel({
name: "A",
selectorToRun: "input[id^='a_']",
funcRun: function (nextThis)
{
var $this = $(nextThis);
var nowDateTime = Date.now();
var i = 0;
while( Date.now() < nowDateTime + 2)
i++;
$this.val( i );
if (i > 100)
$this.css('color', 'green').css('font-weight', 'bold');
else
$this.css('color', 'blue');
}
});
$(document).zParallel({
name: "B",
selectorToRun: "input[id^='b_']",
funcRun: function (nextThis)
{
var $this = $(nextThis);
var nowDateTime = Date.now();
var i = 0;
while( Date.now() < nowDateTime + 2)
i++;
$this.val( i );
if (i > 100)
$this.css('background', '#BBFFBB');
else
$this.css('background', '#FFBBBB');
}
});
})(jQuery);
https://jsfiddle.net/NickU/1xt8L7co/59/
The two example functions simply execute synchronously one after the other on the same "thread" (JS effectively has only one thread available to such scripts).
The use of async is irrelevant here because no truly asynchronous operation is occurring in function A - it is simply a busy while loop - so it completes in full before execution can move to anything else.
If function A had called an actual asynchronous operation (such as a HTTP request - not simply a synchronous operation wrapped in an async function), then function B may have a chance to start up (in which case B would complete entirely before the execution returned to A, because B is also only contains a synchronous, busy while loop).
Parallel processing can be achieved with WebWorkers which allowing running on background threads (actual separate threads).
As my loop is so fast, the intervals are overlapping and not able to stop one timerId. here is my code:
data = ['115536', '117202']; // BARCODES AVAILABLE ON A4 SHEET //
var scan_delay = 500; // USER AVG SCANNING SPEED PER BARCODE //
var timerId;
var scannedItemsList = []; // ITEMS WHICH ARE SCANNED BY SEEING A4 SHEET BY THE USER //
var tableDataList = []; // TO SHOW DATA WHICH WE GOT FROM API //
Jbin
try {
var data = ['115536', '117202']; // BARCODES AVAILABLE ON A4 SHEET //
var scan_delay = 500; // USER AVG SCANNING SPEED PER BARCODE //
var timerId;
var scannedItemsList = []; // ITEMS WHICH ARE SCANNED BY SEEING A4 SHEET BY THE USER //
var tableDataList = []; // TO SHOW DATA WHICH WE GOT FROM API //
execute(data);
function execute(data) {
var i = 0;
scanSimulatorWithADelay(data, i);
}
function scanSimulatorWithADelay(data, i) {
setTimeout(function () {
getJobDetailsByCallingAPI(data[i], i);
i++;
if (data.length > i) {
scanSimulatorWithADelay(data, i);
} else {
i = 0;
}
}, scan_delay);
}
function getJobDetailsByCallingAPI(jobNumber, index) {
scannedItemsList.push(jobNumber);
//poll_for_jobs_count_which_are_scanned_but_waiting_to_add_to_table
startPolling();
//Simulate API to get response after every 3 seconds//
var apiDelay = (index + 1) * 3000;
setTimeout(function () {
console.log('API CALLED AT ' + new Date().toLocaleTimeString());
CallTheAPI(jobNumber);
}, apiDelay);
}
function CallTheAPI(jobNumber) {
console.log("JOB NO " + jobNumber + " API response Recd");
tableDataList.push(jobNumber);
}
function startPolling() {
var pollStatus = '';
timerId = setInterval(() => {
debugger;
console.log('timerId when starting interval ' + timerId);
var jobsWhichAreScannedButNotLoaded = jobsWhichAreScannedButNotLoadedStill();
console.log("$$$$$$ jobsWhichAreScannedButNotLoaded = " + jobsWhichAreScannedButNotLoaded.length);
if (jobsWhichAreScannedButNotLoaded.length === 0) {
console.log("### Inteval Cleared ### " + timerId);
//CLEAR TIMER
clearInterval(timerId);
} else {
pollStatus = 'Polling inprogress and the pollID ' + timerId;
}
console.log('####' + pollStatus);
}, 2000);
}
function jobsWhichAreScannedButNotLoadedStill() {
let stillLoadingJobs = [];
scannedItemsList.forEach(scannedItemsListJobNumber => {
let foundJobInsideTable = false;
if (scannedItemsListJobNumber) {
foundJobInsideTable = tableDataList.indexOf(scannedItemsListJobNumber) > -1;
if (!foundJobInsideTable) {
stillLoadingJobs.push(scannedItemsListJobNumber);
}
}
}); // End of scannedItemsList forEach loop
if (stillLoadingJobs.length > 0) {
return stillLoadingJobs;
}
return [];
}
} catch (error) { throw error; }
Your timer_id variable is on the global scope and hence overwritten every time you call startPolling.
So when you'll call clearInterval(timer_id), timer_id will be the id of the last setInterval, and the first one will keep running endlessly.
Simply add a var in your startPolling function so that timer_id be scoped correctly, and that it doesn't get overwritten by next call.
try {var data = ['115536', '117202'];
var scan_delay = 500;
// remove this one
//var timerId;
var scannedItemsList = [];
var tableDataList = [];
execute(data);
function execute(data) {
var i = 0;
scanSimulatorWithADelay(data, i);
}
function scanSimulatorWithADelay(data, i) {
setTimeout(function () {
getJobDetailsByCallingAPI(data[i], i);
i++;
if (data.length > i) {
scanSimulatorWithADelay(data, i);
} else {
i = 0;
}
}, scan_delay);
}
function getJobDetailsByCallingAPI(jobNumber, index) {
scannedItemsList.push(jobNumber);
//poll_for_jobs_count_which_are_scanned_but_waiting_to_add_to_table
startPolling();
//Simulate API to get response after every 3 seconds//
var apiDelay = (index + 1) * 3000;
setTimeout(function () {
console.log('API CALLED AT ' + new Date().toLocaleTimeString());
CallTheAPI(jobNumber);
}, apiDelay) ;
}
function CallTheAPI(jobNumber) {
$.ajax({
url: "https://jsonplaceholder.typicode.com/todos/1",
type: "GET",
async: true,
success: function (response) {
console.log("JOB NO " + jobNumber + " API response Recd");
tableDataList.push(jobNumber);
}
});
}
function startPolling() {
var pollStatus = '';
/////////
///HERE
/////////
// Declare timerId in startPolling scope
/////////
var timerId = setInterval(() => {
debugger;
console.log('timerId when starting interval '+ timerId);
var jobsWhichAreScannedButNotLoaded = jobsWhichAreScannedButNotLoadedStill();
console.log("$$$$$$ jobsWhichAreScannedButNotLoaded = "+ jobsWhichAreScannedButNotLoaded.length);
if (jobsWhichAreScannedButNotLoaded.length === 0) {
console.log("### Inteval Cleared ### "+ timerId);
//CLEAR TIMER
clearInterval(timerId);
} else {
pollStatus = 'Polling inprogress and the pollID ' + timerId;
}
console.log('####' + pollStatus);
}, 2000);
}
function jobsWhichAreScannedButNotLoadedStill() {
let stillLoadingJobs = [];
scannedItemsList.forEach(scannedItemsListJobNumber => {
let foundJobInsideTable = false;
if (scannedItemsListJobNumber) {
foundJobInsideTable = tableDataList.indexOf(scannedItemsListJobNumber) > -1;
if (!foundJobInsideTable) {
stillLoadingJobs.push(scannedItemsListJobNumber);
}
}
}); // End of scannedItemsList forEach loop
if (stillLoadingJobs.length > 0) {
return stillLoadingJobs;
}
return [];
}
} catch (error) { throw error; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I am using google maps and i am trying to put a pause in execution to prevent QUERY_LIMIT usage issue. My function that plots the addresses looks like this.
The code works, however i want to try setTimeout or setInterval to see if its going to look better on UI.
How do i call it, what should be the first argument?
Thanx alot.
vLocations = [];
for (var i = 0; i < vAddresses.length; i++) {
//pause to prevent OVER_QUERY_LIMIT issue
//geocode "free" usage limit is 5 requests per second
//setTimeout(PlotAddressesAsUnAssigned, 1000);
//sleep(500);
//this will resolve the address and store it in vLocations
AddWaypointAndUnassigned(vAddresses[i]);
var z = i % 4;
if (z==0 && i != 0) {
//sleep after every 5th geocode call
//alert('going to sleep...i: ' + i);
//sleep(3000);
}
}
Doing a pause (asynchronous execution) inside a loop (synchronous) will usually result in a lot of trouble.
You can use recursive calls that are done only when a timeout ends.
var vLocations = [];
// Manages the timeout and recursive calls
function AddWaypointAndUnassignedWithPause(index){
setTimeout(function(){
// When the timeout expires, we process the data, and start the next timeout
AddWaypointAndUnassigned(vAddresses[index]);
// Some other code you want to execute
var z = i % 4;
if (z==0 && i != 0) {
//sleep after every 5th geocode call
//alert('going to sleep...i: ' + i);
//sleep(3000);
}
if(index < vAddresses.length-1)
AddWaypointAndUnassignedWithPause(++index);
}, 1000);
}
// Start the loop
AddWaypointAndUnassignedWithPause(0);
JSFiddle example.
Try this, hope this will help
vLocations = [];
for (var i = 0; i < vAddresses.length; i++) {
//pause to prevent OVER_QUERY_LIMIT issue
setTimeout(function(){
//this will resolve the address and store it in vLocations
AddWaypointAndUnassigned(vAddresses[i]);
}, 500);
var z = i % 4;
if (z==0 && i != 0) {
//sleep after every 5th geocode call
//alert('going to sleep...i: ' + i);
//sleep(3000);
}
}
What about a waiting line, thats fired when an item is added and stopped when there are no items left.
With setTimeout:
var INTERVAL = 1000 / 5;
var to = null;
var vLocations = [];
function addAddress(vAddress) {
vLocations.push(vAddress);
startTimeout();
}
function startTimeout() {
if( to === null ) {
to = setTimout(processLocation, INTERVAL);
}
}
function processLocation() {
if( vLocations.length ) {
var vAddress = vLocations.shift();
AddWaypointAndUnassigned(vAddress);
to = setTimout(processLocation, INTERVAL);
} else {
to = null;
}
}
With setInterval:
var INTERVAL = 1000 / 5;
var to = null;
var vLocations = [];
function addAddress(vAddress) {
vLocations.push(vAddress);
startInterval();
}
function startInterval() {
if( to === null ) {
to = setInterval(processLocation, INTERVAL);
}
}
function processLocation(cb) {
if( vLocations.length ) {
var vAddress = vLocations.shift();
AddWaypointAndUnassigned(vAddress);
} else
clearInterval(to);
to = null;
}
}
How can I force for cycle to wait for every XHR to be completed before it runs? I know a way which is in comment, but it kills real-time of percentage counter.
var data = new Array, per = 0;
WinJS.xhr({url : "http://index.hu/tech/rss"}).done(function(req){
$($.parseXML(req.response)).find("item title:lt(5)").each(function() {
data.push({
h : this.textContent
})
}).next().each(function(ind) {
WinJS.xhr({
url : this.textContent
}).done(function(req) {
per += 100 / 30;
$("#per").text(Math.ceil(per) + " %");
data[ind].p = req.response.match(/<p>(.+?)<\/p>/)[1]
})
/*var req = new XMLHttpRequest;
req.open("get", this.textContent, false);
req.onreadystatechange = function()
{
if(this.readyState == 4)
{
per += 100/30;
$("#per").text(Math.ceil(per) + " %");
data[ind].p = this.response.match(/<p>(.+?)<\/p>/)[1]
}
}
req.send()*/
})
for(var ind in data)
{
//console.log(data[ind].p)
}
})
Instead of using a for loop for that, you could attach a callback function on the XHR request that checks if the stopping condition of the for loop is met, and then stops, or else makes the requisition one more time.
You can just wait using setTimeout. See line setTimeOut(wheAllDone, 100); below:
var items = $($.parseXML(req.response)).find("item title:lt(5)").each(function()
{
data.push(
{
h : this.textContent
})
}).next();
var itemsCount = items.length;
var doneSoFarCount = 0;
items.each(function(ind)
{
WinJS.xhr(
{
url : this.textContent
}).done(function(req)
{
per += 100 / 30;
$("#per").text(Math.ceil(per) + " %");
data[ind].p = req.response.match(/<p>(.+?)<\/p>/)[1]
doneSoFarCount ++;
})
});
var wheAllDone = null;
wheAllDone = function() {
if(doneSoFarCount >= itemsCount)
{
for(var ind in data)
{
//console.log(data[ind].p)
}
} else {
setTimeOut(wheAllDone, 100); // <<<<< Wait a bit for all to complete
}
};
I'm a beginner in Javascript and I'm having some trouble with this code I wrote. It's supposed to create a digital time-clock for my website.
If you're wondering why CPGS is in my functions/variable names it's because its a abbreviation for my website name :)
Also, I am getting NO console errors from FireBug and my JSLint confirms that my code is vaild.
Here's the code:
(function() {
function CpgsClock() {
this.cpgsTime = new Date();
this.cpgsHour = this.cpgsTime.getHours();
this.cpgsMin = this.cpgsTime.getMinutes();
this.cpgsDay = this.cpgsTime.getDay();
this.cpgsPeriod = "";
}
CpgsClock.prototype.checker = function() {
if (this.cpgsHour === 0) {
this.cpgsPeriod = " AM";
this.cpgsHour = 12;
} else if (this.cpgsHour <= 11) {
this.cpgsPeriod = " AM";
} else if (this.cpgsHour === 12) {
this.cpgsPeriod = " PM";
} else if (this.cpgsHour <= 13) {
this.cpgsPeriod = " PM";
this.cpgsHour -= 12;
}
};
CpgsClock.prototype.setClock = function() {
document.getElementById('cpgstime').innerHTML = "" + this.cpgsHour + ":" + this.cpgsMin + this.cpgsPeriod + "";
};
var cpgsclock = new CpgsClock();
setInterval(function() {
cpgsclock.setClock();
cpgsclock.checker();
}, 1000);
})();
So setClock method works fine. But the checker won't do anything. As you can see it checks for the time and sets it to AM and PM accordingly. It doesn't do that for me.
Any help would be great!
You're not updating the clock in your setInterval...
CpgsClock.prototype.update = function() {
this.cpgsTime = new Date();
this.cpgsHour = this.cpgsTime.getHours();
this.cpgsMin = this.cpgsTime.getMinutes();
this.cpgsDay = this.cpgsTime.getDay();
this.cpgsPeriod = "";
};
And in your setInterval :
setInterval(function() {
cpgsclock.update();
cpgsclock.checker();
cpgsclock.setClock();
}, 1000);
jsFiddle : http://jsfiddle.net/qmSua/1/