-
• #2
@CanyonCasa, indeed, there is a difference between Espruino and most JavaScript VMs: If you do a
clearTimeout()
orclearInterval()
which have already fired or been cleared, Espruino is not happy where the others just ignore...A good practice for handling
setTimeout()
s is this pattern:- clear the handle in the timed function
check the handle before clearing the timeout and clear the handle
var timeoutId; // some code... timeoutId = setTimeout(function(){ timeoutId = null; // ...your other code.... }, 10000); // ...other code... // code to clear the timeout ALLWAYS conditioned if (timeoutId) { timeoutId = clearTimeout(timeoutId); }
For
setInterval()
, the pattern is a bit simpler:- check the handle before clearing the interval and clear the handle
In both cases, the handle is a nice 'handle' to know whether a timeout is still going on or an interval is already or still going on.
The pattern for handling timeouts become a bit tricky when the same function is used in multiple, concurrent timeouts. Even though it is easy to pass parameters in the
setTimeout()
and the timed function, the parameter is not ready until timeout construction function returns... Using the 'trick' to pass an object and have it updated afterwards overcomes this hurdle:var timeout1 = {}, timeout2 = {}; function timedFunction(timeout) { timeout.id = null; // ...other code... }; // ...more code... timeout1.id = setTimeout(timedFunction, 1000, timeout1); timeout2.id = setTimeout(timedFunction, 2000, timeout2); // ...some code... if (timeout1.id) { timeout1.id = clearTimeout(timeout1.id); } // ...some code again... if (timeout2.id) { timeout1.id = clearTimeout(timeout2.id); }
Thanks for making me think through this concurrent reuse situation... so far never happened to me and the simple version worked always as desired... and does no harm when cross developing in HTML5 in Browser.
As an allObjects's goodie, you can go all-things-are-objects-crazy and use a full fletched object to handle it nicely with class-y, object-oriented timeout instances. You can give the timeouts even names and some debug support about when set, fired, and cleared... (those fancy enhancements we leave for now with the 'dream(s)'... of which you should never ever make all come true,... running out of dreams: what would life be without dreams...)
// setup the Timeout 'class' with 'clear()' method clearing conditionally function Timeout() { this.id = null; } Timeout.prototype.clear = function() { if (this.id) { this.id = clearTimeout(this.id); } }; // some code... // setup timeout control object var timeout1 = new Timeout(), timeout2 = new Timeout(); // some code... // setup timeouts timeout1.id = setTimeout(timedFunction,1000,timeout1); timeout2.id = setTimeout(timedFunction,2000,timeout2); // some code... timeout1.clear(); // conditioned only when other code needs to be included timeout2.clear(); // conditioned only when other code needs to be included
The extra solution would be luxury Timeout class that wraps the simple language setTimeout() function... but 'boiling the ocean' could backfire: memory waste / 'leaks' (application owned) in memory-frugal MC world...
- clear the handle in the timed function
-
• #3
Thanks @allObjects. Your first example will work for my application, cleaner than my workaround. I've seen this signature before, but haven't needed it for NodeJS, where I do most of my coding these days.
Still, I don't see the value in throwing an error from clearTimeout where undefined could be gracefully returned instead, which doesn't require the user to know to clear the ID in the callback, or think of clearTimeout differently than clearInterval or differently than NodeJs code.
FYI, I think your second example has a couple typos ...var timeout1 = {}, timeout2 = {}; function timedFunction(timeout) { timeout.id = null; // ...other code... }; // ...more code... timeout1.id = setTimeout(timedFunction, 1000, timeout1); timeout2.id = setTimeout(timedFunction, 2000, timeout2); // ...some code... if (timeout1.id) { timeout1.id = clearTimeout(timeout1.id); } // ...some code again... if (timeout2.id) { timeout2.id = clearTimeout(timeout2.id); }
And similarly, I believe you meant line 11 of the last example to reference timeout2.
-
• #4
@CanyonCasa, thanks being so gentle with couple typos... it was more heaps of... anyway...
I had't the opportunity to do much node.js... I'm still heavily involved in all other server technologies, even though JavaScript is my primary choice of language / environment - because it reminds me the most of Smalltalk where everything is an object, hence my forum ID. The last Smalltalk VM's I worked with had JITs that took care of compiling it to machine code beyond byte code and took at the same time care of the primitives (which from my language point of view was one of the very bad things Java introduced from the beginning and only lately added auto conversion for). Client-side I did a lot with emerging JavaScript frameworks and did also demanding Single Page Apps. - I just loved st and am still grateful that it kicked my brain b..t to grok oo and bringing relieve to finally do oo without having just to emulate it (with structured language). Another great thing I liked the very helpful method signature pattern that finally got away with the noise of introduced by the gazillions of parenthesis and commas that C - and practically every other language - still hangs on to... not to talk about the cluttering getter and setter verbosity.
I'm looking forward to hear more from your experience in the forum to pair up the Espruino and node.js worlds, especially when it comes to servers participate in the 'game'.
@Gordon, Tried this with Espruino board 1v4 and Pico running both 1v89 and 1v84 builds, as well as nightly build from @DrAzzy...
Executing the following lines from the clearTimeout reference together (i.e. cut and paste both lines into IDE left pane) works as expected...
But if you enter the first line, wait for the timeout to "fire" (which prints foo), then enter the second line, it results in...
Obviously, when the Timeout fires it internally clears the Timeout ID, but the code leaves id holding what seems to be a "valid Timeout ID". The code outside the timeout has no way of knowing whether or not the timeout has fired, which prevents arbitrarily cancelling a timeout that has potentially occurred. NodeJS does not exhibit this ambiguous behavior. My workaround has been to use a try/catch clause around the clearTimeout as per the example below...