I have some websocket that sends around 100's of data per second,I want to limit it to only 1 data per 500 ms.
onMessage(data) {
console.log(data); // This prints around 100 different times within 1 second
}
I tried something like below , Is this the right approach or is there any other better way to do it ? because this code runs 100 times per second.
var lastlog = new Date().getTime();
onMessage(data) {
currenttime = new Date().getTime();
if ( currenttime - lastlog > 500) {
console.log(data);
lastlog = new Date().getTime();
}
}
P.s : I can ignore remaining data and will be able to reduce the 500 ms to 200ms.. that is 5 data per second.
Here is another way of doing it, using the npm package throttle-debounce. This method is not "better". It can result is less code typed but you might not want the dependency on the package.
You can use the throttle function and specify how many milliseconds until it can be called again. Setting the second argument to true prevents the last request from being deffered -https://www.npmjs.com/package/throttle-debounce#notrailing.
The example below uses the library to throttle how often a button is pressed.
const { throttle } = throttleDebounce
const handleRequest = throttle(500, true, () => {
console.log('this request will be handled')
})
<script src='https://cdn.jsdelivr.net/npm/throttle-debounce#3.0.1/umd/index.js'></script>
<button onClick="handleRequest()">Mimick sending message</button>
Your use case might look like this:
import { throttle } from 'throttle-debounce'
const onMessage = throttle(500, true, () => {
console.log(data);
})
Less lines than your example, but that doesn't mean it's "better".
Related
I have an api request that is called multiple times in a given amount of time. More specifically this request is for refreshing the user token, so it's called on every request, which adds up pretty quickly. I would like to create a function that tells the function not to run for a given amount of seconds. I have tried using lodash debounce but I can't get it to work.
let debounceRefresh;
debounceRefresh = debounce(() => {
api.request(){
});
}, 1000);
debounceRefresh();
Am I executing this wrong? Is it possible to do?
Yes, you definitely need throttle for the job.
// in this example we invoke a fn for a period of 10 sec, invoking it 2 times a second, but we can perceive that the original function is only invoked at most once per 2 seconds according to the parameter below:
var TOTAL_TIME_TO_RUN = 10000; // 10 sec
var THROTTLE_INTERVAL = 2000; // <= adjust this number to see throttling in action
var INVOCATION_INTERVAL = 500; // 0.5 sec
// regular fn
var punchClock = function punchClock() {
console.log(new Date().toISOString() + ' - call api');
};
// wrap it and supply interval representing minimum delay between invocations
var throttledPunchClock = _.throttle(punchClock, THROTTLE_INTERVAL);
// set up looping
var intervalId = setInterval(function() {
console.log("attempting call api");
throttledPunchClock()
}, INVOCATION_INTERVAL);
// run the demo
setTimeout(() => clearInterval(intervalId), 10000)
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.21/lodash.min.js"></script>
<pre>
var TOTAL_TIME_TO_RUN = 10000; // 10 sec
var THROTTLE_INTERVAL = 2000; // < = adjust this number to see throttling in action
var INVOCATION_INTERVAL = 500; // 0.5 sec
</pre>
Snippet from github
Have you tried with a timeout?
const myTimeout = setTimeout(debounceRefresh, 1000);
If the function is called again, you can clear the timeout and reset it
clearTimeout(myTimeout);
Why don't you use a different listener? Perhaps when data is received?
Is it possible to cancel a regex.match operation if takes more than 10 seconds to complete?
I'm using an huge regex to match a specific text, and sometimes may work, and sometimes can fail...
regex: MINISTÉRIO(?:[^P]*(?:P(?!ÁG\s:\s\d+\/\d+)[^P]*)(?:[\s\S]*?))PÁG\s:\s+\d+\/(\d+)\b(?:\D*(?:(?!\1\/\1)\d\D*)*)\1\/\1(?:[^Z]*(?:Z(?!6:\s\d+)[^Z]*)(?:[\s\S]*?))Z6:\s+\d+
Working example: https://regex101.com/r/kU6rS5/1
So.. i want cancel the operation if takes more than 10 seconds. Is it possible? I'm not finding anything related in sof
Thanks.
You could spawn a child process that does the regex matching and kill it off if it hasn't completed in 10 seconds. Might be a bit overkill, but it should work.
fork is probably what you should use, if you go down this road.
If you'll forgive my non-pure functions, this code would demonstrate the gist of how you could communicate back and forth between the forked child process and your main process:
index.js
const { fork } = require('child_process');
const processPath = __dirname + '/regex-process.js';
const regexProcess = fork(processPath);
let received = null;
regexProcess.on('message', function(data) {
console.log('received message from child:', data);
clearTimeout(timeout);
received = data;
regexProcess.kill(); // or however you want to end it. just as an example.
// you have access to the regex data here.
// send to a callback, or resolve a promise with the value,
// so the original calling code can access it as well.
});
const timeoutInMs = 10000;
let timeout = setTimeout(() => {
if (!received) {
console.error('regexProcess is still running!');
regexProcess.kill(); // or however you want to shut it down.
}
}, timeoutInMs);
regexProcess.send('message to match against');
regex-process.js
function respond(data) {
process.send(data);
}
function handleMessage(data) {
console.log('handing message:', data);
// run your regex calculations in here
// then respond with the data when it's done.
// the following is just to emulate
// a synchronous computational delay
for (let i = 0; i < 500000000; i++) {
// spin!
}
respond('return regex process data in here');
}
process.on('message', handleMessage);
This might just end up masking the real problem, though. You may want to consider reworking your regex like other posters have suggested.
Another solution I found here:
https://www.josephkirwin.com/2016/03/12/nodejs_redos_mitigation/
Based on the use of VM, no process fork.
That's pretty.
const util = require('util');
const vm = require('vm');
var sandbox = {
regex:/^(A+)*B/,
string:"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC",
result: null
};
var context = vm.createContext(sandbox);
console.log('Sandbox initialized: ' + vm.isContext(sandbox));
var script = new vm.Script('result = regex.test(string);');
try{
// One could argue if a RegExp hasn't processed in a given time.
// then, its likely it will take exponential time.
script.runInContext(context, { timeout: 1000 }); // milliseconds
} catch(e){
console.log('ReDos occurred',e); // Take some remedial action here...
}
console.log(util.inspect(sandbox)); // Check the results
I'm working on a chatbot script (Hubot - running in terminal) exercise and looking for a method to count the time since the last message was left in the thread. Then after nobody has left a message for X number of minutes (let's say 10,000 milliseconds) I would like to console.log("CRICKETS!..CRICKETS!..")
I'm imagining something like:
//currentTime - startTime = timeSince
//and
// if( timeSince > 10,000)
// {console.log("Crickets!..")
however I'm not sure of how to create the currentTime variable as continuously growing counter
Below is the code I've started which doesn't appear to throw any errors in the , but also doesn't seem to work as I'm running it in the terminal. It just prints the current time twice
module.exports = function(robot) {
return robot.hear(/$/i, function(msg) {
var startTime = (Date.now()) ;
return(startTime);
if (Date.now() - startTime > 1000) {
console.log("CRICKETS..!...")
};
});
};
You'll notice I'm using Date.now() but I'm not attached if there's a better method. Also here is a link to basic hubot scripts in case it is needed for context - https://github.com/github/hubot/blob/master/docs/scripting.md
You can always use setTimeout and cancel it if need be
Pseudo-code:
var myTimeout = setTimeout(function () {
//nobody has left a message for 10 seconds
}, 10000);
if (user has left message)
clearTimeout(myTimeout);
The window.setTimeout function allows you to trigger a callback function after a delay. And you can clear that timeout by calling window.clearTimeout(value_returned_by_setTimeout).
We could define a callback: function crickets(){ console.log('Chirp! Chirp!'); }
Assuming some function newMessage gets called whenever a a new message appears, you could try something like this:
var cricketTimeout = null;
function newMessage(){
//... your code
if (cricketTimeout) clearTimeout(cricketTimeout);
cricketTimeout = setTimeout(crickets, delayInMilliseconds);
}
I'm trying to use Twitter API in order to retweet.And because Twitter has limitation to 2400 actions per day I decided to limit the retweet to one time every 40 seconds.
I'm using https://www.npmjs.com/package/twit using Streaming API.
My problem is that it continuously streams console.log instead of using setInterval.
By stream I mean it outputs console.log multiple times instead of one time.
function hastagRetweet() {
var stream = T.stream('statuses/filter', { track: ['#hastag']})
stream.on('tweet', function (tweet,error) {
var retweetId = tweet.id; // id
var retweetId_str = tweet.id_str;
var tweetTextRetweet = tweet.text; // tweet text
function twInterval() {
console.log('INFO ------- ',tweet.id);
console.log('INFO ------- ',tweet.text);
};
setInterval(twInterval, 1000 * 40);
});
}
Any way of getting the variales data retweetId,retweetId_str,tweetTextRetweet outside stream.on beside inserting them into a mysql table so that every 40 seconds it checks the variables fixed data and executes console.log?
There are multiple problems here:
You're trying to start an interval timer in an event handler. That means that every time the event fires you would be attempting to start a new interval timer and they would pile up.
Even if you did sucessfully start up an interval timer, each one would never change it's output since the variables in scope for it never change as it is started up within a given function and the arguments to that function are what they were when it was first called. Subsequent calls of the function will start a new function not change the arguments on the prior call of the function.
You aren't even starting your interval correctly. As it is, all you're doing is calling the function and passing it's return value to setInterval() which does nothing.
If the goal is just to output to the console each stream tweet event, then probably what you want is just this:
function hastagRetweet() {
var stream = T.stream('statuses/filter', { track: ['#hastag']})
stream.on('tweet', function (tweet,error) {
var retweetId = tweet.id; // id
var retweetId_str = tweet.id_str;
var tweetTextRetweet = tweet.text; // tweet text
console.log('INFO ------- ',tweet.id);
console.log('INFO ------- ',tweet.text);
});
}
You cannot get these variables outside the .on() handler. It's an async callback and the only place they reliably exist is within that handler.
If you can describe in more detail what the end result you're trying to achieve is, we can likely help more specifically. If you want to do something every 40 seconds, then maybe you need to collect data in some collection (probably an array) and then every 40 seconds evaluate what you have just recently collected.
Here's a method of collecting the events in an array and then evaluating them every 40 seconds:
function hastagRetweet() {
var stream = T.stream('statuses/filter', { track: ['#hastag']});
var tweets = [];
stream.on('tweet', function (tweet,error) {
tweets.push({id: tweet.id, str: tweet.id_str, text: tweet.text});
});
setInterval(function() {
// evaluate the tweets in the tweets array every 40 seconds
// do something with them
for (var i = 0; i < tweets.length; i++) {
// tweets[i].id
// tweets[i].str
// tweets[i].text
}
// reset the tweets array
tweets.length = 0;
}, 40 * 1000);
}
Please note that once you call hastagRetweet(), it will run forever.
I am attempting to build a webapp on a Chromebook, I need it to read RFID card serial numbers with an ACR122U NFC. I am using chrome-nfc.
I am reading cards happily, but I do not know how to fire an event when a card is presented.
Are there any events in chrome-nfc I can use to know when a card has been presented to the reader?
EDIT: I have been trying to use chrome.nfc.wait_for_tag, but it does not behave as I would expect.
// With a card on the reader
chrome.nfc.wait_for_tag(device, 10000, function(tag_type, tag_id){
var CSN = new Uint32Array(tag_id)[0];
console.log ( "CSN: " + CSN );
});
[DEBUG] acr122_set_timeout(round up to 1275 secs)
DEBUG: InListPassiveTarget SENS_REQ(ATQA)=0x4, SEL_RES(SAK)=0x8
DEBUG: tag_id: B6CA9B6B
DEBUG: found Mifare Classic 1K (106k type A)
[DEBUG] nfc.wait_for_passive_target: mifare_classic with ID: B6CA9B6B
CSN: 1805372086
// with no card on the reader
chrome.nfc.wait_for_tag(device, 10000, function(tag_type, tag_id){
var CSN = new Uint32Array(tag_id)[0];
console.log ( "CSN: " + CSN );
});
[DEBUG] acr122_set_timeout(round up to 1275 secs)
DEBUG: found 0 target, tg=144
Both return the results as above immediately, it does not seem to matter what number I use for a timeout...
If I call the function with no card on the reader, and then immediately put the card on the reader after function call, I get no output in the console.
I'm not familiar with chrome-nfc, but taking a shot in the dark by reverse engineering the source, it looks like you would want to use the wait_for_tag method, like:
chrome.nfc.wait_for_tag(device, 3000, function(tag_type, tag_id) {
// Do your magic here.
});
...Where device is your reader, 3000 is the maximum time to wait (in ms), and replacing // Do your magic here. with your desired logic. If it times out, both tag_type and tag_id will be null.
If you wanted to wait indefinitely, you could just recursively call a function with the above code. Example:
function waitAllDay(device) {
chrome.nfc.wait_for_tag(device, 1000, function(tag_type, tag_id) {
if(tag_type !== null && tag_id !== null)
{
// Do your magic here.
}
waitAllDay(device);
});
}
That's assuming you want it to continue waiting even after a tag has been presented. Wrap the waitAllDay(device); in an else if you want it to stop once a tag is read.
UPDATE: It seems the wait_for_tag method does not work as intended, so I'm proposing a second solution. I'm leaving the existing solution in place in case the method is fixed by the developers of chrome-nfc.
Another thing to try is to use chrome.nfc.read, passing in a timeout option, inside a window.setInterval.
var timer = window.setInterval(function () {
chrome.nfc.read(device, { timeout: 1000 }, function(type, ndef) {
if(!!type && !!ndef) {
// Do your magic here.
// Uncomment the next line if you want it to stop once found.
// window.clearInterval(timer);
}
});
}, 1000);
Be sure and call window.clearInterval(timer) whenever you want it to stop watching for tags.
While I do not consider this a proper solution; here is a workaround I am using for the time being.
function listen_for_tag(callback, listen_timeout){
var poll_delay = 400; //ms
var listen_loop = null;
if(!listen_timeout){
listen_timeout = 99999999;
}
function check_for_tag(){
if(listen_timeout < 0) {
clearInterval(listen_loop);
console.log("we didnt find a tag. finished");
}
chrome.nfc.wait_for_tag(dev_manager.devs[0].clients[0], 10, function(tag_type, tag_id){
console.log ( "FOUND A TAG!!" );
clearInterval(listen_loop);
// handle the callback (call it now)
var C = callback;
if (C) {
callback = null;
window.setTimeout(function() {
C(tag_type, tag_id);
}, 0);
}
});
listen_timeout -= poll_delay;
}
listen_loop = setInterval(check_for_tag, poll_delay);
}