I am having newbie difficulties implementing clearInterval with a certain payload.
The
if(msg.payload.state === "OFF")
works, but the timer doesn't stop.
Amongst many resources, I have seen how to stop setInterval in JS in node-red..?, node.js: how to use setInterval and clearInterval?, clearInterval doesn't clearInterval & clearInterval On Image Slider Plugin
I did have a similar function, "dominos" that I used to make sure I was parsing the "OFF" payload.
I have included a lot of commented code to show what I had tried. Sorry about the mess!
Is it an issue with my syntax?
Is the code logical?
var input = msg.payload.state;
let timer = 0;
var red = {"state":"ON","brightness":255,"color":{"r":255,"g":0,"b":0}};
var green = {"state":"ON","brightness":255,"color":{"r":0,"g":255,"b":0}};
function xmas() { // REPEATS!
node.send({payload:red});
setTimeout(function(){
node.send({payload:green});
}, 1500);
}
// repeat with 3 second interval
timer = setInterval(() => xmas(), 3000);
if (msg.payload.state === "OFF") {
timer = clearInterval();
}
The important thing to remember about a function node is that it's state is totally reset for each incoming message. This means that timer will ALWAYS be reset to zero by the let timer = 0;
If you want to store any state between messages then you need to use the context.
Also the way you are using clearInterval() will never work, you need to pass the reference to the timer object to this function for it to do anything useful.
The following function node should do what I think you intended.
var red = {"state":"ON","brightness":255,"color":{"r":255,"g":0,"b":0}};
var green = {"state":"ON","brightness":255,"color":{"r":0,"g":255,"b":0}};
if (msg.payload.state != "OFF") {
var timer = setInteval(()=>{
node.send({payload: red});
setTimeout(() => {
node.send({payload: green});
}, 1500);
}, 3000);
context.set("timer",timer);
} else {
var timer = context.get("timer");
clearInterval(timer);
}
Related
So I'm working with websockets to process data from website's API. For every new event I also send some http requests back to the website in order to obtain more data. Up untill now everything has worked fine, but now that I started using async requests to speed it up a bit things got a bit different. My code used to process one event and then move on to the next one (these events come in extremely quick - around 10 per second) but now it just seems to ignore the async (non blocking) part and move on to the next event and that way it just skips over half of the code. Note that the code works fine outside the Pusher. I'm using the 'pusher-client' module. My code looks like this:
var Request = require("request");
var requestSync = require('sync-request');
var Pusher = require('pusher-client');
var events_channel = pusher.subscribe('inventory_changes');
events_channel1.bind('listed', function(data)
{
var var2;
//Async request (to speed up the code)
function myFunction(callback){
request("url", function(error, response, body) {
if (!error && response.statusCode == 200)
{
result = JSON.stringify(JSON.parse(body));
return callback(null, result);
}
else
{
return callback(error, null);
}
});
}
myFunction(function(err, data){
if(!err)
{
var2 = data
return(data);
}
else
{
return(err);
}
});
//The part of the code below waits for the callback and the executes some code
var var1 = var2;
check();
function check()
{
if(var2 === var1)
{
setTimeout(check, 10);
return;
}
var1 = var2;
//A CHUNK OF CODE EXECUTES HERE (connected to the data from the callback)
}
});
In conclusion the code works, but not inside the pusher due to the pusher skipping the asynchronous request. How would I make the pusher wait for my async request to finish, before processing the next event (I have no idea)? If you happen to know, please let me know :)
You need to implement a queue to handle events one after another. I'm curious how it worked before, even without Pusher you'd have to implement some queue mechanism for it.
const eventsQueue = []
events_channel1.bind('listed', function(data) {
eventsQueue.push(data)
handleNewEvent()
})
let processingEvent = false
function handleNewEvent() {
if (processingEvent) return // do nothing if already processing an event
processingEvent = true
const eventData = eventsQueue.shift() // pick the first element from array
if (!eventData) return // all events are handled at the moment
... // handle event data here
processingEvent = false
handleNewEvent() // handle next event
}
Also, you should call clearTimeout method to clear your timeout when you don;t need it anymore.
And it's better to use promises or async/await instead of callbacks. Your code will be much easier to read and maintain.
I am learning node js and need some clarification.
var EventEmitter = require('events').EventEmitter;
var getResource = function(c) {
var emitter = new EventEmitter();
process.nextTick(function() {
var count = 0;
emitter.emit("start")
var t = setInterval(function() {
c
emitter.emit("data", ++count);
if (count === c) {
emitter.emit("end");
//clearInterval(t);
}
}, 1000)
});
return emitter;
}
var r = getResource(5);
r.on("start", function() {
console.log("I have started");
})
r.on("data", function(d) {
console.log("Received " + d);
})
r.on("end", function() {
console.log("I have ended");
})
If I uncomment the setInterval part it behaves as expected ie., prints the data until 5 and end event is emitted.
If I comment it, then data is printed until 5 and end event is emitted. After that it runs in indefinite loop and prints continuously. Why is my code
if(count === c){...}
does not check and ends the loop ?
The emit method is a generic one. It just emits an event & optionally passes data.
emitter.emit(eventName, data);
where eventName is a string & data is an arbitrary value.
It is up to the programmer to make use of that as per the requirement.
Passing end as event name means nothing to emit method, as for the method, it is just another call. In your case, clearInterval is needed to actually end data events. Only to the receiver of the events, end event makes sense.
So, if you emit end event, the receiver will know there would be no more data event.
Consider emitting end event as a signal to receiver. But, you have to actually make sure there are no more events(data) after end event.
until clearInterval is called, setInterval will execute the code
in recurring time intervals.
Please refer the NodeJs doc on Timers.
I've implemented a native function which takes a callback. NodeJS knows the interface, but it doesn't know anything about its implementation. This native function receives a callback and will call it when the result is ready. I don't want the event loop to exit while the callback hasn't been called.
Here is an example of such a problem.
Currently I need to do some I/O (even if it's a dumb timeout) to force NodeJS to wait for my function.
In Boost.Asio I'd just instantiate a work object and destroy it when the callback is called. Boost.Asio's event loop wouldn't exit while this object is kept around. Is there a similar approach for NodeJS? What do I use in NodeJS (bonus if your answer doesn't mention timers)?
The best way to do that would be writing a C++ addon and using one of the handles offered by libuv (of course, the one that fits your requirements - see the official documentation for further details).
If you don't want to do that or if you can't do that (that is the case, if I've correctly understood the question), a viable solution not mentioned in the other answers is using process.nextTick to schedule a function that checks at each tick if the loop can expires or not.
see here for further details about process.nextTick.
As a minimal, working, never-ending example:
var process = require('process')
var stop = false;
var f = function() { if(!stop) process.nextTick(f) }
f()
This way your function is in charge of setting the stop control variable once it finishes to execute, then the loop will stop.
If you have multiple callbacks to wait for, simply use a counter and check it looking for 0.
If you don't want to explicitly set and update the value of the counter each time you add a new function (error-prone), you can easily write a launcher to start your functions that increments the counter and schedules a check on the next tick if needed.
You could also pass a callback as an extra argument to your functions to notify when they are over, so that they have not to deal explicitly with the counter itself.
A plus of using a dedicated function that is scheduled on the next tick is that it's clear to the reader what you are doing.
On the other side, a fake server, a timeout scheduled in the future or an I/O stream resumed and never used are quite obscure, for the reader doesn't know immediately why you are doing that.
Method 1: Create a dummy server(updated for multiple callback):
var counter = 0;
var server = require('net').createServer().listen(); // <-- Dummy server
console.log('Dummy server start.');
var ffi = require('ffi'),
ref = require('ref')
var lib = ffi.Library('./libffi_async_demo', {
'print_thread_id': [ 'void', [] ],
'run_delayed': [ 'void', [ 'pointer' ] ],
});
var checkExit = function (){
counter--;
if (counter===0) {
server.close(); // <-- exit Dummy Server
console.log('Dummy server stop.');
}
}
// Wrapper for lib.run_delay()
run_delay = function(cb) {
counter++; // <-- increase counter
lib.run_delayed(cb);
}
var callback1 = ffi.Callback('void', [], function() {
console.log("js callback1 started");
lib.print_thread_id();
console.log("js callback1 finished");
checkExit(); // <-- call at the end of each callback
})
var callback2 = ffi.Callback('void', [], function() {
console.log("js callback2 started");
lib.print_thread_id();
console.log("js callback2 finished");
checkExit(); // <-- call at the end of each callback
})
var callback3 = ffi.Callback('void', [], function() {
console.log("js callback3 started");
lib.print_thread_id();
console.log("js callback3 finished");
checkExit(); // <-- call at the end of each callback
})
run_delay(callback1); // use wrapper
run_delay(callback2); // use wrapper
run_delay(callback3); // use wrapper
Method 2: Long timeout, callback end process
var timeout; // Hold timeout reference from setTimeout()
var ffi = require('ffi'),
ref = require('ref')
var lib = ffi.Library('./libffi_async_demo', {
'print_thread_id': [ 'void', [] ],
'run_delayed': [ 'void', [ 'pointer' ] ],
});
var callback = ffi.Callback('void', [], function() {
console.log("js callback started");
lib.print_thread_id()
console.log("js callback finished");
// Use one of the following 3:
//timeout.unref(); // <-- remove timer from Node event loop
//require('process').exit(); //<-- end process
clearTimeout(timeout); // <-- cancel timer
})
lib.run_delayed(callback)
timeout = setTimeout(function() { }, 3600000); // <-- reasonably long timeout, eg. 1hr
You can also use the stdin Readable stream to hold on exiting the loop.
const callback = ffi.Callback('void', [], function() {
// do your stuff here
// switch stream out of flowing mode.
process.stdin.pause();
});
// set stream into flowing mode ("old mode")
process.stdin.resume();
lib.run_delayed(callback);
Reference: the Note in https://nodejs.org/api/process.html#process_process_stdin
Start repl somewhere in your code, it will prevent your app from exit.
const repl = require('repl');
repl.start('> ')
When you are done just call
process.exit()
https://nodejs.org/api/repl.html
create big timeout - it'll prevent node from exiting and also guards you from waiting indefinitely for (external to node) result:
var ffi = require('ffi'),
ref = require('ref')
var ffiTimeout;
var lib = ffi.Library('./libffi_async_demo', {
'print_thread_id': [ 'void', [] ],
'run_delayed': [ 'void', [ 'pointer' ] ],
});
var ffiDidTimedOut = false;
var cancelFfi = function(timeoutCb) {
return function() {
ffiDidTimedOut = true;
timeoutCb();
}
}
var callback = ffi.Callback('void', [], function() {
if (ffiDidTimedOut) {
return; // sorry, we waited too long and already started doing something else
}
// all good, async ffi finished within expected time and we are back in our js land
clearTimeout(ffiTimeout);
lib.print_thread_id()
})
lib.run_delayed(callback)
// continueIfCancelledCallback is your continuation "what to do id ffi actually takes more than 20 seconds to run"
ffiTimeout = setTimeout(cancelFfi(continueIfCancelledCallback), 20000); // 20 seconds
I'm building my first node.js application on my Raspberry Pi which I am using to control an air conditioner via LIRC. The following code is called when you want to increase the temperature of the AC unit. It sends a LIRC command every 250 milliseconds depending on how many degrees you want to increase it by. This code works as expected.
var iDegrees = 5;
var i = 0;
var delay = 250 // The delay in milliseconds
function increaseTemperatureLoop(){
i++;
//lirc_node.irsend.send_once("ac", "INCREASE", function() {});
console.log(i);
// Call the fucntion/loop again after the delay if we still need to increase the temperature
if (i <= iDegrees){
timer = setTimeout(increaseTemperatureLoop, delay);
}
else {
res.json({"message": "Success"});
}
}
// Start the timer to call the recursive function for the first time
var timer = setTimeout(increaseTemperatureLoop, delay);
I'm having a hard time working with the asynchronous nature of node.js. Once my recursive function is done, I return my json to the browser as shown in the code above. By habit, I feel like I should return the json in a line of code after my initial function call like below but obviously that wouldn't wait for all of the LIRC calls to be successful - it seems silly to have it inside of the function:
var timer = setTimeout(increaseTemperatureLoop, delay);
res.json({"message": "Success"});
What if I have a bunch of other stuff to do after my LIRC sends are done but before I want to send my json back to the browser? Or what if that block of code throws an error...
My second question is, how do I properly wrap the LIRC call in a try/catch and then if there is an error, stop the recursive calls, pass the error back up, and then pass this back to the browser along with the actual error message:
res.json({"message": "Failed"});
For track end of the cycle execution task, you can use a callback.
In order to know whether completed all routine tasks, you can use the task queue.
Monitor and report bugs to the top - it is possible with the help of
three of the same callback.
In general, it is desirable to wrap everything into a single object.
Some example for reflection:
var lircTasks = function __self (){
if (typeof __self.tasks === "undefined") __self.tasks = 0;
__self.func = {
increaseTemperature: function() {
// lirc_node.irsend.send_once("ac", "INCREASE_TEMPERATURE", function() {});
},
increaseFanPower: function() {
// lirc_node.irsend.send_once("ac", "INCREASE_FANPOWER", function() {});
}
}
var fab = function () {
__self.tasks++;
this.i = 0;
this.args = arguments[0];
this.callback = arguments[1];
this.run = function __ref(taskName) {
if (taskName) this.taskName = taskName;
if (this.i<this.args.deg) {
try {
__self.func[this.taskName]();
} catch(e) {
__self.tasks--;
this.callback( {message: "error", error: e, taskName: this.taskName, task: this.args, tasks: __self.tasks} );
}
this.i++;
setTimeout( __ref.bind(this), this.args.delay );
} else {
__self.tasks--;
this.callback({message:"complete", taskName: this.taskName, task: this.args, tasks: __self.tasks});
}
}
}
if ((arguments.length === 2) && (typeof arguments[1] === "function") && arguments[0].deg>0 && arguments[0].delay>=0) {
return new fab(arguments[0], arguments[1]);
}
}
function complete(e) {
console.log(e);
if (e.tasks === 0) console.log({message: "Success"});
}
lircTasks( {deg: 10, delay:100, device: "d1" }, complete ).run("increaseTemperature");
lircTasks( {deg: 20, delay:150, device: "d2" }, complete ).run("increaseTemperature");
lircTasks( {deg: 5, delay:100, device: "d3" }, complete ).run("increaseFanPower");
Here is my situation, I need to speed up the function running time, so setInterval is not a wise choose, right? Since it will cost at least 4ms for each time.
So, may I change setInterval function to requestAnimationFrame, but I don't quite understand how the requestAnimationFrame works.
For example
// some code here
var interval = setInterval(doSomething, 10)
var progress = 0
function doSomething(){
if (progress != 100){
// do some thing here
}else{
clearInterval(interval)
}
}
and how can I apply requestAnimationFrame?
I think the key to understand requestAnimationFrame lies in paul Irish's explanation:
Any rAFs queued in a rAF will be executed in the next frame
from requestAnimationFrame Scheduling For Nerds
var rafReference;
var progress = 0;
function doSomething(){
// only run 100 times
if (progress < 100){
/* do what you wanna do here */
progress++;
//recursively calls it self as requestAnimationFrame's callback
rafReference = requestAnimationFrame(doSomething) // passed as reference
}else{
cancelAnimationFrame(rafReference)
}
}
//starting the recursion
requestAnimationFrame(doSomething)
Looks better in a fiddle-->just the code,no animation
Every thing is commented inside the code for simplification.No need of using setInterval.
Just use cancelAnimationFrame when we are suppose to clear interval.
// This makes sure that there is a method to request a callback to update the graphics for next frame
var requestAnimationFrame =
window.requestAnimationFrame || // According to the standard
window.mozRequestAnimationFrame || // For mozilla
window.webkitRequestAnimationFrame || // For webkit
window.msRequestAnimationFrame || // For ie
function (f) { window.setTimeout(function () { f(Date.now()); }, 1000/60); }; // If everthing else fails
var cancelAnimationFrame =
window.cancelAnimationFrame ||
window.mozCancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.msCancelAnimationFrame;
// your code here
var progress = 0;
function doSomething() {
if (progress != 100) {
// do something here
var myAnimation = requestAnimationFrame(doSomething);
} else {
// don't use clearInterval(interval) instead when you know that animation is completed use cancelAnimationFrame()
cancelAnimationFrame(myAnimation);
}
}
Some Links worth a read-->
CreativeJs---the best explanation any one could give,Every begineer must read
CancelAnimationFrame
link 3-->in context of your question
I found this fiddle on google,quite the same that you want.
Other things that you should know:
RAF is still in the development stage.
Why doesn't jQuery use requestAnimationFrame?