Is it possible in NodeJS to implement a version of setTimeout that wouldn't block the process from exiting once the last line of code has finished?
i.e. the kind of conditional setTimeout that would only trigger the callback function provided the process is still running.
Practical example:
When implementing a library that initializes itself by setting up some timeouts, you would want that once the app has finished, you don't need to make an explicit call into that library to clear all the timeouts, and let the app shut down regardless.
You can use clearTimeout if you wanted to maintain references to all your outstanding timers and then clear them as part of your application exit process, but it is much easier in node to use unref() Node doc on unref. The effect is that any unrefed timer will not prevent Node from exiting.
For example:
var to = setTimeout(myFunction,delay);
to.unref();
Works with setInterval as well
setInterval(myFunction,delay).unref();
If you look at the docs for setTimeout, you will notice that it returns a timeoutObject that can be used to cancel the timeout via clearTimeout(obj).
So what you could do is keep track of all the timeouts you create by storing their id objects. Then you are able end all the timeouts whenever you want.
If you simply want to exit the process, ignoring everything else, you can just use process.exit() (passing an argument if you want to return a non zero error code).
Related
I have an interval set to run a function every 5 minutes: const timer = setInterval(func, TIMEOUT)
This starts when a specific object is created and I use clearInterval to stop it once a condition is met. This works as expected in practice. However, there are certain tests (using chai and sinon) that result in the creation of the object, though they are not specifically testing the creation of the object. This leads to the creation of the interval, which prevents the tests from every finishing.
I saw in node there is timer.unref(), which sounds like it would work for me, but in practice since setInverval in js returns an id, I get a type error Timer.unref is not a function
Is there a way to stop an interval in javascript when the test process ends?
Edit: The creation of the object exists in one package, as part of an API call, and the tests are calling the API from another package, so do not have access to the creation of the object nor the timer. The condition which clears the interval is not (and cannot) be met in the tests.
I built a nodejs application that should execute several tasks.
My app.js has a function call to the manager module which controls those tasks.
I want to call that function from my app.js and perform those tasks every 30s.
something like:
setInterval(manager.tasks(), 30000);
My question is that if using setInterval could give me any performance problems (slowing down the computer, blocking resources or any other reason)
Is there a more efficient way to do this or is setInterval ok?
it depends on how heavy the work/processing you want to do is, setInterval is async so your code will only be run once every 30 seconds, but at the same time JavaScript is single-threaded, so if you're doing a lot of work in your task, the one time it runs in 30 seconds it may take too long to execute thus blocking resources.
In most cases you should be fine using setInterval, but if you really want to emulate multi-threading or if you're doing too much work in your task, you may want to spawn another child process https://nodejs.org/api/child_process.html process or use the new Worker Threads API https://nodejs.org/api/worker_threads.html instead, but keep in mind its not as simple to implement as a setInterval call
Use node-cron or node-schedule instead
setInterval is implemented in standard node js, you won't have any performance / blocking problems, most libraries also use setInterval
It completely depends on the function you executing inside setInterval. If it is I/O bound operation then you don't need to worry too much because libuv will handle itself But if it is CPU bound then I will suggest you to use child_process api to fork a new child process and do your stuff in to that.
Let's say I do this:
var timer = setTimeout(function() {
console.log("will this happen?");
}, 5000);
And then after just less than 5 seconds, another callback (from a network event in NodeJS for example) fires and clears it:
clearTimeout(timer);
Is there any possibility that the callback from the setTimeout call is already in the queue to be executed at this point, and if so will the clearTimeout be in time to stop it?
To clarify, I am talking about a situation where the setTimeout time actually expires and the interpreter starts the process of executing it, but the other callback is currently running so the message is added to the queue. It seems like one of those race condition type things that would be easy to not account for.
Even though Node is single thread, the race condition the question describes is possible.
It can happen because timers are triggered by native code (in lib_uv).
On top of that, Node groups timers with the same timeout value. As a result, if you schedule two timers with the same timeout within the same ms, they will be added to the event queue at once.
But rest assured node internally solves that for you. Quoting code from node 0.12.0:
timer.js > clearTimeout
exports.clearTimeout = function(timer) {
if (timer && (timer[kOnTimeout] || timer._onTimeout)) {
timer[kOnTimeout] = timer._onTimeout = null;
// ...
}
}
On clearing a timeout, Node internally removes the reference to the callback function. So even if the race condition happens, it can do no harm, because those timers will be skipped:
listOnTimeout
if (!first._onTimeout) continue;
Node.js executes in a single thread.
So there cannot be any race conditions and you can reliably cancel the timeout before it triggers.
See also a related discussion (in browsers).
I am talking about a situation where the setTimeout time actually expires and the interpreter starts the process of executing it
Without having looked at Node.js internals, I don't think this is possible. Everything is single-threaded, so the interpreter cannot be "in the process" of doing anything while your code is running.
Your code has to return control before the timeout can be triggered. If you put an infinite loop in your code, the whole system hangs. This is all "cooperative multitasking".
This behavior is defined in the HTML Standard, the fired task starts with:
If the entry for handle in the list of active timers has been cleared, then abort these steps.
Therefore even if the task has been queued already, it'll be aborted.
Whether this applies to Node.js, however, is debatable, as the documentation just states:
The timer functions within Node.js implement a similar API as the timers API provided by Web Browsers but use a different internal implementation that is built around the Node.js Event Loop.
Right now I have a jQuery plugin that adds some extra customization (around how to handle the return data in certain contexts) and polling a server for information and changes. One of the required features is to allow the user set the polling interval. setTimeout (paired with recursion) is the function that is used for creating the constant poll; this is also a requirement.
This is where I am stumped: along with the required functionality noted above, I also have to test if the user-specified value was actually used in the setTimeout. How would I go about doing this from a QUnit perspective?
I have already pondered straight timing the function with Date.getTime(), but the way things are currently set up this isn't an option.
Consider refactoring the code in a way that let's you override the method starting the timeout within your test, allowing you to verify that the correct value is passed, without actually starting the timeout.
If you need to actually call setTimeout, consider using sinon.js to mock setTimeout itself and control what it does instead.
I'm currently experimenting with embedding V8 in a project of mine. Since I use libev for listening to sockets and events and want to be able to script events with JS I would want to be able to just run v8 for a short while and then jump back to C++ to check for events and such and then go back to running JS-code. Since I haven't done much script embedding earlier I'm sure there are some clever way that this usually is done in so all ideas are appreciated.
The cleanest way I found of doing this is to create setTimeout and clearTimeout functions within JS. setTimeout creates a ev::Timer which has a callback that gets called after a certain amount of time. This makes it so that when you call a JS function you continue to execute that until it returns, but that function can set a number of timeouts which aren't called until after you exit the current JS and there hasn't happened any other libev events during the execution, in that case those are handled first (in C++). The limitations of this method is that the coder who writes JS has to remember to not write functions that goes into eternal while-loops or similar. A loop is instead done like this:
function repeat() { setTimeout(repeat, 0); }