Is there any way to create an alarm for which it guarantees to be triggered at a provided time? Chrome does provide the chrome.alarms API which can be used to create alarms, however the system may delay the alarm indefinitely:
chrome.alarms.create({
when: startTime,
periodInMinutes: 60 // is not actually triggered every hour
});
The same thing goes with setTimeout:
function update(){
console.log(new Date());
setTimeout(update, 1 * 60 * 1000); // also isn't triggered every minute
}
Just after 10 minutes of the computer being idle, the update loop starts being delayed.
I'm looking for a way to guarantee an alarm going off at a defined time (given the computer is on and the extension is loaded, of course).
Related
Background
Suppose I have a metaphorical patient whose heart beats once per second, and every second, I check whether his last heartbeat was more than five seconds late (and, if so, declare him to be in danger):
let lastHeartbeat = Date.now();
// Heartbeater
setInterval(() => lastHeartbeat = Date.now(), 1000);
// Health-checker
setInterval(
() => {
if((Date.now() - lastHeartbeat) > 5000){
alert("Patient has flatlined");
}
},
1000
);
Issue
If I use a debugger to pause the execution of this script at some point, I have a problem: if I remain on a breakpoint for more than five seconds, then, once script execution resumes, my health-checker function is certain to declare that the patient has flatlined.
Desired behaviour
Instead, I'd like to factor in the time spent in the debugger.
i.e., if I spend twenty seconds sitting on a breakpoint just after an initial heartbeat occurring, and the patient's heart beats again within just one second of releasing that breakpoint, then that patient should not be declared as flatlining.
Is there any way to subtract the time spent in the debugger from the health-check condition? e.g.:
if((Date.now() - lastHeartbeat - lastTimeSpentInDebugger) > 5000)
Note: I'm specifically running the JS in Node.js, rather than in a browser.
I've got a countdown on my website done with setTimeout() but I realize that with Internet Explorer 11 (and older I guess) when the user right clicks anywhere on the browser, the countdown just stops because the "context menu" from the browser is open. The countdown starts back when the context menu is close.
The solution of blocking the rightclick during this countdown is not an usable solution in my case.
I've also check the requestAnimationFrame() method, but if the user minimize the browser, the countdown also stops.
The countdown is not lasting forever, it can last from 3 minutes to 10 seconds.
Any workaround/ideas ?
Thanks
You can't rely on setTimeout or setInterval to track time. They will approximately run when they are meant to but it is dependent on what else is taking up processing time and some blocking events like you have discovered. You should think of them as a way to update your clock but maintain the clock state as a differential between the time you started and the time your timer function fires. Because the timing of when the function fires isn't exact I try to set the interval lower than what I want. If I want it to tick every second then I set the interval to a half or quarter second to ensure that I make up for misses quicker.
Here is a rough example:
function countdown(duration) {
const start = Date.now();
const interval = window.setInterval(function() {
const remaining = duration - (Date.now() - start);
if (remaining <= 0) {
console.log(0);
window.clearInterval(interval);
return;
}
console.log(remaining);
}, 500);
}
countdown(5000);
I have some Javascript which is executed every day on sunset. Since the time of sunset varies every day, I set a new timer for tomorrow once the current sunset timer is executed.
scheduleSunTimer(timer) {
let _timer = timer;
let time = getSunset(new Date(), config.latitude, config.longitude);
schedule.scheduleJob(time, () => {
this.console.log('Timer actived');
// Reschedule for next day
this.scheduleSunTimer(_timer);
});
}
I use the node-schedule library from https://github.com/node-schedule/node-schedule/
This code works for a while, but after a week my application hangs. It looks like the callback of schedule.scheduleJob calling scheduleSunTimer again creates some never ending nested call stack. This might cause a memory leak which causes my app to crash.
I was wondering if anyone know how to avoid the call stack from growing, or might know a better solution / best practise for this.
I write extension for Chrome. And I need run delayed tasks when background page inactive. Cause setTimeout not working in background tabs, I try emulate setTimeout with setInterval, like code below (located in content script):
window.timings = [];
function set_timeout(func, time){
var now = new Date() / 1;
window.timings.push({
func: func,
time: time + now
});
}
function tick(){
var now = new Date() / 1;
window.timings = window.timings.filter(function(delay_obj){
if (now > delay_obj.time){
delay_obj.func.call();
return false;
} else {
return true;
}
});
}
$(function() {
setInterval(tick, 1000);
// some code
});
And it don't work when set_interval call in delay function:
set_timeout(function(){
console.log('func1');
}, 2000);
set_timeout(function(){
console.log('func2');
set_timeout(function(){
console.log('func3');
}, 3000);
}, 3000);
Output:
func1
func2
Why func3 not displayed?
You're apparently using an event page declared with "persistent": false in manifest.json, it is unloaded after 15 seconds of inactivity. The linked documentation says to use chrome.alarms API.
For a delay less than 15 seconds since the last chrome event:
Use setTimeout or setInterval.
For a delay of 15-60 seconds since the last chrome event:
Don't use the event page, switch to "persistent": true in manifest.json.
For a delay of 60 seconds or more:
manifest.json:
"permissions": ["alarms"],
background script:
chrome.alarms.create("MyInterval1", {when: Date.now() + 1 * 60e3});
chrome.alarms.onAlarm.addListener(function(alarm) {
if (alarm.name == "MyInterval1") {
console.log("Yay!");
chrome.alarms.create("MyInterval1", {when: Date.now() + 1 * 60e3});
}
});
Also note:
Other asynchronous HTML5 APIs like notifications and geolocation will not complete if the event page shuts down. Instead, use equivalent extension APIs, like notifications.
If your extension uses, extension.getBackgroundPage, switch to runtime.getBackgroundPage instead. The newer method is asynchronous so that it can start the event page if necessary before returning it.
Note that in a published extension the interval between the next alarm and the last fired alarm is at least 1 minute even if you specify a smaller value like 15 seconds (15*1000).
Source: https://developer.chrome.com/docs/extensions/reference/alarms/#method-create
In order to reduce the load on the user's machine, Chrome limits
alarms to at most once every 1 minute but may delay them an arbitrary
amount more. That is, setting delayInMinutes or periodInMinutes to
less than 1 will not be honored and will cause a warning. when can
be set to less than 1 minute after "now" without warning but won't
actually cause the alarm to fire for at least 1 minute.
To help you debug your app or extension, when you've loaded it
unpacked, there's no limit to how often the alarm can fire.
I'm reading a book called Pro Javascript Techinques(John Resig)
a piece of code of the core-animation is as follwing
setTimeout(function () {
elem.style['width'] = (i / 100) * fullwith + 'px';
}, **(i + 1) * 10** );
I wonder while it should change the 'each-timeout' time to implement it
why the 'each-timeout' time should not be the same,eg:1000,It flash consequently
Thanks so much~
Each setTimeout registers a new timeout (all starting "now") that will fire 10ms apart, thus you do get a regular pulse every 10ms, but you queue all of them up in advance — the first timeout doesn't fire until 10ms after you've registered all of these callbacks.
Why he should do it that way when there's setInterval, I don't know — maybe interesting to find out, is it in the book?