The problem
I am saving pictures in my IndexedDB on the browser. I want to call a function in javascript every 10 seconds to sync the URL's in the IndexedDB to my real database.
It should be down in the backgroud. This means: There should be a function which will be called every 10 seconds to automaticall "sync" the entries in the database.
What i have done
I have already a "sync"-Button/functionality which works fine. This function should be called automatically. But this function in the background should not interrupt or distrubt my main functions in the foreground. For example adding new entries in the indexedDB.
During my research i found the folliwing function:
setInterval(function(){ alert("Hello"); }, 3000);
But it just works alone and not parallel with my "main"-functions.
The ideal solution
The ideal solution should be a function (i have the function already) which will be triggered ever 10 seconds (it don't have to be really 10 seconds, this is just a sample number) but should not disurpt other functions by executing.
If you just want to call your function again and again, try this code using setTimeInterval:
/* The data param is in case you want to pass some param */
var mySynFunc = (data) => {
console.log(`Sync my data: ${data}`);
}
/* This id must be used to stop your function interval */
var id = setInterval(mySynFunc, 3000, 'my-url');
/* If you want to stop your setIntervalFunction use this */
clearInterval(id)
Related
I have a webpage that I'm using to print 'pages' of data as PDF files via the firefox 'Print to File' printer on my laptop. The code I'm invoking is as follows:
document.body.controls.cmdPrint.click = function () // Create a function that will be called when this object is clicked upon
{if (parseInt(document.body.controls.page.innerHTML) !== 0) // If we are not on the Front Cover
{return false;} // Function complete: Abnormal Termination
document.body.controls.style.pointerEvents = 'none'; // Lock down the controls so they cannot be interfered with
do // Do...
{window.print(); // Print this page
// document.body.sleep(); // Removed as this does not work as expected (see below...)
} while (document.body.controls.cmdNext.click()) // ...while we are able to advance.
document.body.controls.style.pointerEvents = ''; // Release the controls lockout
this.blur(); // Blur the focus
return true;}; // Function complete: Normal Termination
When executing, the pages flip as expected (as the cmdNext.click() function returns a true when successful and a false when it's on the last page and trying to advance), but it runs too quickly. Namely every odd page is caught out, as the 'printer' is unavailable....the window.print() is being released before the printer is ready for the next page.
I tried slowing down execution by adding a reference to a secondary function within the loop (now commented out), but this just locks up the CPU and keeps the printer from processing in another thread....so it's not a valid solution. This function (which I wrote but did not provide the expected cushioning to allow odd pages to print) is as follows.
document.body.sleep = function (delay) // Create a new function
{delay = delay || 1; // Default to a delay of 1 second
var timestamp = new Date(); // Get current time
timestamp = new Date(timestamp.getTime() + (delay * 1000)); // Add in the delay (in seconds)
while (new Date() < timestamp) {} // While we are waiting for the delay, do nothing
return true;}; // Function complete: Normal Termination
Basically what I need is a way to hold loop execution long enough to let the 'Print to File' to go through before the next window.print() is called. Using the sleep function above also keeps the window.print() from running even though (when I was trying to use it as a fix) I had put the call to this function immediately after the window.print() command.
So I ask, can anyone here supply a fix for this project so I don't have to manually cycle through each page (which could get annoyingly temporally expensive with a page count above 10)?
As it is currently, when the second page tries to print, I get the popup window holding an error from firefox: "Printer Error - Some printing functionality is not currently available." Tracking this down lead to PERR_NOT_AVAILABLE....probably because the printer (Print to File) is busy printing the prior page....so I just need to wait for that to resolve before going to the next printing. An error handler to catch this PERR_NOT_AVAILABLE instead of letting it bounce to the user (me) as a popup window that has to be clicked out of would be nice, though a spammy way of getting the pages to print in sequence as quickly as the Print to File system can process them.
If window.print() actually returned an error in this condition, I could just rerun the command...
In my experimentation, I found this workaround...it's quite fairly considered a kludge, but in the absence of a more elegant solution, it works.
document.body.controls.cmdPrint.click = function () // Create a function that will be called when this object is clicked upon
{if (parseInt(document.body.controls.page.innerHTML) !== 0) // If we are not on the Front Cover
{return false;} // Function complete: Abnormal Termination
document.body.controls.style.pointerEvents = 'none'; // Lock down the controls so they cannot be interfered with
window.onafterprint = function () // Set up a handler for after a print operation
{setTimeout(function () // Run a delayed operation
{if (document.body.controls.cmdNext.click()) // Move to next page and if this is successful
{window.print(); // Continue printing
return false;} // Function complete: Still Printing
do // Do nothing...
{} while (document.body.controls.cmdPrevious.click()) // ...while we cycle back to the start
document.body.controls.style.pointerEvents = ''; // Release the controls lockout
this.blur(); // Blur the focus
window.onafterprint = function () {}; // Remove this handler
return true;}, 2000);}; // Function complete: Normal Termination
window.print(); // Begin printing the page
return true;}; // Function complete: Normal Termination
If a page is too complex to print to PDF in 2 seconds, that 2000 figure in the setTimeout() will have to be increased to account for it. For my test case (the current 7 page document), 2000 seems to be the sweet spot between not-working and spitting out pages as quickly as Firefox will permit on my system.
I have a jQuery Mobile web app which targets iOS and Android devices. A component of the application is a background task, which periodically checks for a.) changes to local data and b.) connectivity to the server. If both are true, the task pushes the changes.
I'm using a simple setTimeout()-based function to execute this task. Each failure or success condition calls setTimeout() on the background task, ensuring that it runs on 30 second intervals. I update a status div with the timestamp of the last task runtime for debugging purposes.
In any desktop browser, this works just fine; however, on iOS or Android, after some period of time, the task stops executing. I'm wondering if this is related to the power conservation settings of the devices--when iOS enters stand-by, does it terminate JavaScript execution? That is what appears to happen.
If so, what is the best way to resume? Is there an on-wake event which I can hook into? If not, what other options are there which don't involve hooking into events dependent on user interaction (I don't want to bind the entire page to a click event just to restart the background task).
Looks like Javascript execution is paused on MobileSafari when the browser page isn't focused. It also seems if setInterval() events are late, they are simply fired as soon as the browser is focused. This means we should be able to keep a setInterval() running, and assume the browser lost/regained focus if the setInterval function took much longer than usual.
This code alerts after switching back from a browser tab, after switching back from another app, and after resuming from sleep. If you set your threshold a bit longer than your setTimeout(), you can assume your timeout wouldn't finish if this fires.
If you wanted to stay on the safe side: you could save your timeout ID (returned by setTimeout) and set this to a shorter threshold than your timeout, then run clearTimeout() and setTimeout() again if this fires.
<script type="text/javascript">
var lastCheck = 0;
function sleepCheck() {
var now = new Date().getTime();
var diff = now - lastCheck;
if (diff > 3000) {
alert('took ' + diff + 'ms');
}
lastCheck = now;
}
window.onload = function() {
lastCheck = new Date().getTime();
setInterval(sleepCheck, 1000);
}
</script>
Edit: It appears this can sometimes trigger more than once in a row on resume, so you'd need to handle that somehow. (After letting my android browser sleep all night, it woke up to two alert()s. I bet Javascript got resumed at some arbitrary time before fully sleeping.)
I tested on Android 2.2 and the latest iOS - they both alert as soon as you resume from sleep.
When the user switches to another app or the screen sleeps, timers seem to pause until the user switches back to the app (or when the screen awakens).
Phonegap has a resume event you can listen to instead of polling for state (as well as a pause event if you want to do things before it is out of focus). You start listening to it after deviceReady fires.
document.addEventListener("deviceready", function () {
// do something when the app awakens
document.addEventListener('resume', function () {
// re-create a timer.
// ...
}, false);
}, false);
I use angular with phonegap and I have a service implemented that manages a certain timeout for me but basically you could create an object that sets the timer, cancels the timer and most importantly, updates the timer (update is what is called during the 'resume' event).
In angular I have a scopes and root scope that I can attach data to, my timeout is global so I attach it to root scope but for the purpose of this example, I'll simply attach it to the document object. I don't condone that because you need should apply it to some sort of scope or namespace.
var timeoutManager = function () {
return {
setTimer: function (expiresMsecs) {
document.timerData = {
timerId: setTimeout(function () {
timeoutCallback();
},
expiresMsecs),
totalDurationMsecs: expiresMsecs,
expirationDate: new Date(Date.now() += expiresMsecs)
};
},
updateTimer: function () {
if (document.timerData) {
//
// Calculate the msecs remaining so it can be used to set a new timer.
//
var timerMsecs = document.timerData.expirationDate - new Date();
//
// Kill the previous timer because a new one needs to be set or the callback
// needs to be fired.
//
this.cancelTimer();
if (timerMsecs > 0) {
this.setTimer(timerMsecs);
} else {
timeoutCallback();
}
}
},
cancelTimer: function () {
if (document.timerData && document.timerData.timerId) {
clearTimeout(document.timerData.timerId);
document.timerData = null;
}
}
};
};
You could have the manager function take a millisecond parameter instead of passing it into set, but again this is modeled somewhat after the angular service I wrote. The operations should be clear and concise enough to do something with them and add them to your own app.
var timeoutCallback = function () { console.log('timer fired!'); };
var manager = timeoutManager();
manager.setTimer(20000);
You will want to update the timer once you get the resume event in your event listener, like so:
// do something when the app awakens
document.addEventListener('resume', function () {
var manager = timeoutManager();
manager.updateTimer();
}, false);
The timeout manager also has cancelTimer() which can be used to kill the timer at any time.
You can use this class github.com/mustafah/background-timer based on #jlafay answer , where you can use as follow:
coffeescript
timer = new BackgroundTimer 10 * 1000, ->
# This callback will be called after 10 seconds
console.log 'finished'
timer.enableTicking 1000, (remaining) ->
# This callback will get called every second (1000 millisecond) till the timer ends
console.log remaining
timer.start()
javascript
timer = new BackgroundTimer(10 * 1000, function() {
// This callback will be called after 10 seconds
console.log("finished");
});
timer.enableTicking(1000, function(remaining) {
// This callback will get called every second (1000 millisecond) till the timer ends
console.log(remaining);
});
timer.start();
Hope it helps, Thank you ...
You should use the Page Visibility API (MDN) which is supported just about everywhere. It can detect if a page or tab has become visible again and you can then resume your timeouts or carry out some actions.
I am writing a chat application that can have many chat windows open at once. Every time a window is opened I call a setInterval on my function, update_chat(), that updates an individual chat window. I pass the chat_id to update_chat()
setInterval("update_chat("+chat_id+")",4000);
chat_id is just the id of the chat. So I can have the function update_chat running multiple times on different intervals depending on how many chats are open. Start the chat works fine.
My main question is how can I stop the interval above. I don't want to stop all intervals, just the one associated with a particular chat. I tried this
clearInterval("update_chat("+chat_id+")");
but it didn't do anything.
I tried
var chat_intervals=[]
chat_intervals[chat_id]=setInterval("update_chat("+chat_id+")",4000);
clearInterval(chat_intervals[end_id]);
It didn't stop the interval
clearInterval(docs) takes an interval ID as a parameter to know which interval to clear. setInterval (docs) returns an interval ID when called, so you store that in a var and pass it to clearInterval when you want that one to clear.
//start the interval, store its ID
var interval_id = setInterval( function () { /* do something*/ }, 1000);
//clear the interval
clearInterval(interval_id);
Note that setTimeout (docs) and clearTimeout (docs) work with each other in the same way.
Also note that while setInterval can take a string argument as the function to run, it can also take actual functions (which is highly preferred). So your code could be better written as:
var update_chat_interval = setInterval(function () {
update_chat(chat_id);
}, 4000);
// to clear it later:
clearInterval(update_chat_interval);
I'm trying to dynamically create PDFs on a webserver using PHP/wkhtmltopdf, which involves sending the PDF-generation process to the background in order to prevent the page timing out.
To check whether the job has completed successfully, I've used Javascript (which I suck at) and more specifically jQuery/AJAX to continuously query the server looking to see if wkhtmltopdf's process has ended. If its still running, the PHP script returns nothing and simply exits. If the process has ended successfully, a html link to the PDF is generated and then dumped into a <div></div>.
All the server side code works flawlessly however I'm stuck on the Javascript component. The code below kinda works but instead of the timer stopping after a PDF has been generated, it continues to query the server. How do I get it to stop?
$('#pdfmodal').on('shown', function () {
pdf(); // fire PDF generation process function
(function worker() {
$.ajax({
url: 'pdfpidcheck.php',
success: function(data) {
if(data == ''){
// Schedule the next request if nothing returned (i.e. still running)
setTimeout(worker, 5000);
} else {
// dump link to pdf
$('.pdfmodal').html(data);
}
}
});
})();
})
To stop a timer, you just remember the returned value from setTimeout() and call clearTimeout() on it.
var id = setTimeout(fn, 5000);
// then some time later
clearTimeout(id);
In the code you've shown us, this should not be an issue unless you are calling worker() from some other place than what you show us or unless the .on() handler gets called a second time while a PDF is being created. Your current code doesn't look like it knows how to handler two PDFs being created at the same time or a second even triggered while the first one is still processing.
You could protect against multiple timers running like this:
$('#pdfmodal').on('shown', function () {
var modal = $(this);
pdf(); // fire PDF generation process function
(function worker() {
$.ajax({
url: 'pdfpidcheck.php',
success: function(data) {
var timer = modal.data(timer);
if(data == ''){
// make sure we never have more than one timer running
if (timer) clearTimeout(timer);
// Schedule the next request if nothing returned
// (i.e. server process still running)
timer = setTimeout(worker, 5000);
// save timer for later use
modal.data("timer", timer);
} else {
// clean up timer data
if (timer) clearTimeout(timer);
modal.removeData("timer");
// dump link to pdf
$('.pdfmodal').html(data);
}
}
});
})();
})
I am creating a chrome extension and I need to use an interval.
The time the interval will go off every time is chosen by the user itself.
The function executes on every open tab and sends data to it.
My problem is that the "timer" dosn't work like it should, it just execute all at once like a normal while loop.
Here is the code:
chrome.tabs.query({}, function (tabs) {
//the times the code need to run is by the amount of tabs that is open
setInterval(function () {
if (i < tabs.length) {
chrome.tabs.sendRequest(tabs[i].id, { input: "uCanSend",
userName: myName,
password: myPass,
subject: mySubject, msg: myMsg,
linkName1: myLinkName1,
linkURL1: myLinkURL1,
linkName2: myLinkName2,
linkURL2: myLinkURL2
}, function (response) { });
}
i++;
}, timeInMintus //the time that the code need to run every time);
});
I have no idea what am I doing wrong.
Any idea how to fix it that it will run correctly?
(sorry for my English)
The second argument needs to be in milliseconds (thousandths of a second). Based on the variable name, it looks like you're passing minutes. For example, if you want the callback to run every minute:
setInterval(function () { /* snip */ }, 1000*60);
Chrome queues up setTimeout/setInterval calls on inactive tabs and changes the minimal timeout length.