Unsubscribing to a closed variable inside its own callback - javascript

I only want to listen to something once. Is this valid javascript?
const unsubscribe = obj.onFoo(x => {
unsubscribe()
// do things
})

Yes, this is a perfectly valid way of calling unsubscribe().
Even though the function is not assigned to the unsubscribe variable until after the function is constructed, it is not run until the callback is called. When the callback is called, it looks for the unsubscribe identifier and finds it in the enclosing scope. The identifier resolves to the unsubscribe function, and so unsubscribe() is called as you would expect.
This is a fairly common pattern. Just one example off the top of my head is clearing a $watch function in AngularJS – Unbinding $watch in angularjs after called

Related

using flush on lodash's throttle decorator

Using TypeScript (JavaScript and Angular):
I want lodash's throttle decorator to limit an API call while the user is navigating around the page, but still fire before they unload (leave) the site.
In the typescript constructor I have window.addEventListener('beforeunload', () => this.onUnload());
with the onUnload() function being declared as
onUnload() {
this.thisIsTheThrottledFunction.flush;
}
but I am getting the error response "Property 'flush' does not exist on type '() => Promise'."
The function whose .flush method I am trying to access is the declared throttled version of the other function. The function is successfully throttled, so I am confident that part of the code works. What is the best way to access the .flush method?
You should be able to debug this by verifying what the value of this is. Seems to me like you just need to bind the object's this value to the onUnload function (or you can pass it in). For instance, you could put this in your constructor: this.onUnload = this.onUnload.bind(this). There's a sugar for this syntax, where you define it in your class using onUnload = () => { ... }. Both of those methods attach the method to the instance instead of just having it as part of the prototype. Or, you could pass the bound function directly to your event listener:
window.addEventListener('beforeunload', this.onUnload.bind(this));

React binding function

I have seen a lot of reactjs places where a function is called like below
onChange = {this.fileSelected}
whereas I have seen its usage like below as well
onClick={() => this.clearDisplay()}
I want to ask if they both mean the same or is there any difference and what to use when.
If you use First:
onChange = {this.fileSelected}
It will only execute when onChange is called. If you want to bind this function then you have to declare it in the component class constructor like this:
constructor(props) {
super(props);
this.state = {
// your state
};
this.clearDisplay = this.clearDisplay.bind(this);
}
The Second one:
onClick={() => this.clearDisplay()}
This defines an anonymous function but, does not call it. Only when onClick is fired is it called. However, in some cases using an anonymous function can cause performance issues. That anonymous function will be defined on every render - and if you have a component that is re-rendering very often it can hurt the performance of your application. If you are sure that the component will not be rendered often, an anonymous function should be fine for convenience.
onChange={this.fileSelected}
Is preferable because it is able to not cause unnecessary re-renders.
onClick={() => this.clearDisplay()}
When you pass an anonymous function like this it will actually be called on all instances of the class instead of the one that the event was triggered on.
From a high level in may seem like they have the same behavior but if you were to use the second method consistently through a large codebase the performance of your application would suffer.
This article goes more in depth on the issue:
https://medium.freecodecamp.org/why-arrow-functions-and-bind-in-reacts-render-are-problematic-f1c08b060e36
onChange = {this.fileSelected}
This will direct bind fileSelected function to onChange method. so when onChange method called it will call fileSelected function.
while
onClick={() => this.clearDisplay()}
This will call onClick function in which you are calling clearDisplay function. so when you onClick method called, first anonymous called in which clearDisplay function called. So basically in this method two functions called. in this methos you can do additional calls or other things
e.g.
onClick={() => {
console.log("this function called")
this.clearDisplay();
}

Why "() => this.tick()" and "this.tick()" are not the same?

I am looking at this code: https://reactjs.org/docs/state-and-lifecycle.html
I do not understand why I need to use () => this.tick() instead of just this.tick(). The prior calls a function that uses this.tick(), yet when I change () => this.tick() to this.tick(), the code stops working. this.tick() is no longer being called even though it itself is a function. () => this.tick() seems to be just an unnecessary step and yet it is necessary.
I think I am misunderstanding functions as objects.
Thank you
If you pass () => this.tick() then you are passing a function.
If you pass this.tick() then you are passing the value returned by the function.
setInterval(func, delay[, param1, param2, ...]) expects a function as first parameter.
() => this.tick() is a function that when executed will call this.tick() with the appropriate context. If you didn't want to use arrow syntax, you would need to bind the this context similar to this.tick.bind(this);
The arrow function used there is needed to bind the this context, so that it can use this in it's own function.
If you would have only setTimeout( this.tick, 1000 ), it would rightfully call the function on the class, however, that function wouldn't have a this scope...
...unless you bind the this scope in the constructor, or as part of the setTimeout call itself
To do it in the constructor you would have something like
class Clock extends Component {
constructor() {
super();
this.tick = this.tick.bind(this);
}
// other functions
tick() {
this.setState(/*.. state content ..*/):
}
}
another option would be the
setTimeout( this.tick.bind( this ), 1000 );
but that would do the same as what the arrow function is doing for you anyhow, so why not use the arrow function instead.
Another option would be the experimental class properties where you would still have an arrow function, but as this is not the most optimal solution when it comes to testing, I will not directly discuss that one
Firstly, setInterval takes a function as a parameter. Hence unless this.tick returns a function, passing this.tick() to setInterval is incorrect.
setInterval defers the callback method in the event loop. And hence at the time of its execution, the current reference to this will have been lost, as its scope is within its parent function which would have completed its execution. So this would be pointing to window or undefined ins strict mode.
To make it work, you need to preserve the reference, for which we create a closure by creating a new function () => this.tick. Now the reference will be preserved even after parent funtion completes its execution.
You need to give the function a callback to be invoked. A callback is a function that is to be executed after another function has finished. For example using a setTimeout is a built-in function, you give tick a callback because once setTimeout is finished you would like tick to be invoked.
Hope this helps!

Why arrow function is not passing arguments?

I'm using angular w/ rxjs to observe user events on the interface. However, I'm having this really simple problem with passing arguments to a method in an arrow function. Here is the problem:
This is not working: searchterm is not being passed to this.searchFacilities
ngOnInit() {
this.searchTerm$.subscribe(searchterm => this.searchFacilities);/**Not working here**/
}
searchFacilities(term: string){
console.log(term);
this.facilityservice.searchFacilities(term)
.subscribe(results => this.facilityList = results);
}
But this works:
this.searchTerm$.subscribe(searchterm => { this.searchFacilities(searchterm); })
Clearly, I have other solutions that are pretty painless, but I really want to understand why my first approach is not working. Thanks!
Because the parameter is not passed directly to your function.
Example from the doc:
Rx.Observable.range(0, 3).subscribe(function (x) { console.log(x) });
The same example with an arrow function:
Rx.Observable.range(0, 3).subscribe(x => console.log(x));
Small clarification. The doc says you need to pass a callback to subscribe() and that this callback will receive the value(s) emitted by the observable.
We could write it like this:
const myCallBack = (val) => console.log(val);
Observable.range(0, 3).subscribe(myCallBack);
In your case you already have a callback, this.searchFacilities.
This means you can simply write:
this.searchTerm$.subscribe(this.searchFacilities);
Just like you can rewrite my original example to:
// Now `console.log` is the callback!
Observable.range(0, 3).subscribe(console.log);
In other words, the problem is not "Why arrow function is not passing arguments". The problem is that you created an arrow function whose body IS your callback, instead of just using your callback directly.
The expanded version of your code would look like this:
const myCallBack = (searchterm) => {
return this.searchFacilities;
}
As you can see, searchFacilities is neither invoked nor does it receive the searchterm param.
You could have run into the same problem with a NON-ARROW function by writing the following code (although the syntax of arrow functions does make the mistake more likely and insidious):
const myCallBack = function(searchterm) {
return this.searchFacilities;
}
Because you're getting a reference to the searchTerm but you're not doing anything with it. You could just do this.searchTerm$.subscribe(this.searchFacilities) and the term will be passed into the function.
You searchFacilities function is declared in global scope, and then is called inside of ngOnInit as a callback and its context is not anymore global scope, now this points to ngOnInit element Object. In order to work inside ngOnInit object you need to bind it and then searchFacilities be method of ngOnInit and in this way its going to work.

Updating parameters to JavaScript callback before it returns, without using globals

I'm working on making a modification to a node.js module to improve error handling for one of my uses cases. The specifics of the module aren't really relevant, but one of the things I want to do is trigger a delayed retry when receiving a certain status code from the response to an API request. To do this I'm using the timeOut function to trigger a new call to the function after a period of time.
The structure of the code looks like this:
Outer function (parameters specified by client application)
——API request (using parameters)
——Callback from API request (response with status code)
——If error, set timeout to call outer function after delay
However, I also want to handle the case that the outer function is called again while waiting for the timeout. I don't want any calls to trigger a new API request while a timeout is pending, but I do want the parameters from the most recent call to be used when the timeout finishes.
I've been able to get this working using variables that are global to the module. Each time a new call comes in to the outer function it updates a global object with the new parameters then, if a timeout is pending, returns without calling the API request. The timeout function uses the parameters from the global object to call the outer function, rather than the parameters from when it was set. This way it always uses the most recent values that were passed into the outer function, but doesn't make duplicate API calls.
Here's a simplified example of how I've achieved this behavior with global variables: JSFiddle. Hit run a few times until you get a "failure response" which then triggers the timeout.
This works, but I would prefer not add these global variables into the module if there's a better way.
Is there any way to get this same behavior but have all of the state encapsulated in the outer function without using globals? I'm also open to completely rethinking the way I'm handling this if anyone has ideas.
You're not going to be able to do this without creating variables outside of your outer function, however it's still possible to create those variables without polluting your global scope.
To do so, wrap your outer function in another function that gets executed immediately, sometimes known as an IIFE:
mainFunction: (function() {
var savedParam1;
var savedParam2;
var savedParam3;
var pendingTimeout = false;
return function(param1, param2, param3) {
savedParam1 = param1;
savedParam2 = param2;
savedParam3 = param3;
if (pendingTimeout) {
log('pending timeout -- ignoring new call');
return;
}
/* and so on */
}
})(); // the () causes the outer function to run immediately,
// which creates a scope for the savedParam / pendingTimeout variables,
// and then returns the inner function (your old outer function)
// to be used for mainFunction

Categories