Defer, debounce or timeout an event - javascript

I have two events
cy.on('mousedown touchstart', 'node', function (event) {
// start
});
cy.on('mouseover tapdragover', 'node', function (event) {
// end
});
The problem is that the second event is almost immediately fired since the first event was fired when the mouse is being pressed on a node and the second is fired when the mouse is over a node.
Is it possible to debounce or defer the action? I know the syntax is cytoscape.js-specific, but I guess the regular possibilities of using debounce and defer apply.
I guess an easy solution would be to save a timestamp in the first event and check if endTime - startTime > threshold in the second event.

Yes, just use Lodash: cy.on('evt1 evt2 ...', _.debounce( handler ))

Related

clearTimeout doesn't clear timer, it seems too late to clear it

I'm trying to console.log the input value when the keyup event get fired, but similar to debounce implementation, from all posible events happened within a range of 1000 miliseconds I want the last one to be fired.
With clearTimeout(timer) any previous timer get cleared then a fresh timer is set. So from my view, on entering a string the logs would be like:
g
ggg
gggggg
ggggggg
Never be repeted.
let timer = null;
function withdelay() {
clearTimeout(timer);
timer = setTimeout(() => {
handleChange();
}, 1000);
}
function handleChange() {
console.log(document.getElementById("texto").value);
}
<input type="text" id="texto" onkeyup="withdelay()" />
The problem comes when the time between keyup events is close to the delay (1000 miliseconds), the logs are the same.
Why does that happen?, is there any solution based on this lines?
Here is what I think; once the callback of the timer is load from the task queue to the call stack to be executed the clearTimeout(timer) cannot take effect so the callback continue its execution.
The problem here is how keypress vs keyup fires.
keypress fires when the character is added.
keyup is fired when the key is done being pressed.
So when you release the key the value has already been written. It is not written when you release the key. So the timer picks up the change slightly before you release.
Depending on what you are actually trying to do you may want to use oninput or onkeydown

Given an array of EventEmitters, listen for only the first event

In my code, I have an array of EventEmitter objects. I know that at some point, one of them will fire an event called launched.
I only want to listen for the first event fired by an emitter in this array, and ignore any subsequent events.
My current code is:
emitterArray.forEach(emitter => {
emitter.once('launched', () => { console.log('Event fired!') });
});
However, this will wait for every emitter in the array to fire the event once.
I want the program to end after the exactly one of the emitters has fired this event exactly once.
Note: Terminating the process with process.exit in the event listener is not an option.
In your module, you can initialise a global (top module level) flag to false and make every event handler to check for that flag.
if (flag) {
return
}
flag = true
console.log('Event fired')
Since node.js is single-thread, you shouldn't get any race conditions there and even when all the event handlers will get triggered, you can control which of them will actually run its code.
Hope this makes sense.

onChange / onInput alternatives?

I'm creating a typing test page and running into a small issue.
I'm trying to start the timer when the user types, and using onInput works, but the problem is that it registers every time I type into the textArea which causes the starttimer function to repeat itself.
onChange works but it only works after I click outside the page which makes sense, but is not what im looking for. I need the timer to start as soon as the user starts typing. Also with onChange the stop function works, but the timer starts after i click outside of the page.
Is there a JS event that fits what i'm looking for, or is there a way to change onInput or onChange to fix the problem i'm having.
JavaScript
document.getElementById("test-area").onchange = function () {
startTimer(1);
};
Thank you.
You need to listen to the input event because as you said change is only triggered after the input loses focus which is not what you want. You also need to handle the event only once.
document.getElementById("test-area").addEventListener("input", () => {
startTimer(1);
}, {once: true});
Note that this removes the event handler after it is fired. If you need to run it again you will have to register the event one more time. Maybe in your timer callback.
Try like this, In JavaScript, using the addEventListener() method:
The addEventListener() method attaches an event handler to the specified element.
document.getElementById("test-area").addEventListener("change", function () {
if(!this.value.length){
startTimer(1);
}
}, {once : true});
Have you tried onfocus ? its not exactly when they start typing but it works. Another option would be that you use onInput and on the clocks start function change a boolian -isRunning - to true. then put a if (isRunning) return. something like:
function start() {
if(isRunning) return;
isRunning = true;
}
and then change the boolian to false when you stop onChange
Some solutions:
Variant 1
Just create a flag:
var timerStarted = false; // Was the timer started?
document.getElementById("test-area").oninput = function () {
if(timerStarted) return; // If timer was started - do nothing
startTimer(1); // Else - start the timer
timerStarted = true; // Remember what we've started the timer
};
Variant 2
(A bit shorter)
document.getElementById("test-area").addEventListener("input", function () {
startTimer(1);
}, {once: true}); // Good thing about addEventListener
// With this it will run the event only single time
More here: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
Can you use JQuery? If so it has a method .one() which will execute the function only once. You can freely use keydown/keyup event handler then. For eg.
<script>
$(document).ready(function(){
$("#test-area").one("keydown", function() {
alert("hey");
});
});
</script>

Using Underscore _.debounce() to trigger a single event

I have the following function that is being called from a keyPress listener on an input text field. The _.debounce() is working correctly, except instead of only firing the function 1 time after the time period, it is firing as many times as the keyPress event happened.
console.log("Pre Debounce");
var debounced = _.debounce(function() {
console.log("Field updated!");
}, 2000);
debounced();
Is there a way to limit the _.debounce function to only fire 1 time after the time period?
Possibly you are constructing the debounce function each time inside the event. If that's your case then take your debounce function outside the event response code. As far as I know the debounced function should be generated only one time and then be called multiple times.
Another thing that could go weird is when you are making an async call (ex. with an ajax autocomplete) and it takes more than your wait time for debounce then the requests could fire later making appear that debouncing is not working.
It's possible that your debounce function is taking longer to execute than the user to type. In this case, you want to make sure that you prevent double debouncing by passing in a third argument (immediate) as true.
The debounce function signature is: _.debounce(function, wait, [immediate])
So change the code to:
console.log("Pre Debounce");
var debounced = _.debounce(function() {
console.log("Field updated!");
}, 2000, true);
debounced();

Stop pending actions for jquery debounce on keyup (And double keypress)

I have some code that is using a plugin called debounce.
Plugin information: https://code.google.com/p/jquery-debounce/
I've run into a problem where the keypress events still run after keyup event because of the delay from debounce.
For instance... if you were to double click spacebar, the function still runs even though you didn't hold it down for over a second.
It's hard to explain my issue. I basically need a stop() function to run after keyup event to stop any more text being appended.
Here is an example:
http://jsfiddle.net/cTZJU/133/
Code:
function appendFunc() {
$('.output').append('Keypress running');
}
//Debounce the function running too often
$(document).keypress($.throttle(appendFunc, 1500));
$(document).keyup(function() {
/**
* I want to stop any pending keypress actions.
* - Including double keypress
*/
});
Thank you very much in advance.
Use $(document).clearQueue(); in the function called on keyup.
$(document).keyup(function() {
$(document).clearQueue();
});
You will have to bind each event on the document as a queue then only you can use clearQueue.
You can do it like as follows:
$(document).queue(function(){
$(this).keypress(function(){ });
});

Categories