Passing a pointer/reference to a variable as parameter - javascript

I know this question has been asked multiple times (yes, I did some research) but I can't see to find a solution that fits my needs.
What I have done so far:
I was building a function that tracked the percentage of how far the user scrolled down a page and display this nicely into some progressbar. This worked perfectly but when I opened the developer console on Chrome and looked at the Timeline tab (this displays what is being run in a nice graphic), I realised that my code was quite "active". It ran every pixel the user scrolled down the page, which is quite alot to be honest.
So I thought to myself, how can this be improved and I have come up with a solution that involves executing a function only once per {whatever} milliseconds. This involves a variable set to true or false, if the function has already been executed in the {whatever} milliseconds.
What i want to accomplish:
I want to be able to set a reference to an external variable that will act as a flag to determine if the function has already been executed or not.
function qeue(fn, interval, status){ // this function name might not be very fitting..
// fn = function to be executed
// interval = function can only run once between the intervals
// status = tricky part..
// This should contain a reference to an external variable that is either true or false
}
How can this be accomplished?
side note
If this explanation isn't helping, and you still don't get what I want:
How can I pass a reference to a variable into a function, so that function can act based on the value of that variable?
Why normal parameters are not an option
I want to implement some sort of recursive setTimeout functionality inside a function, that checks if another function has been executed or not, if I pass this in to a parameter, this parameter cannot change during the process.
Hope you guys can help me out!
Thank you
Thank you for all your great answers. You made me learn alot. I am going with the debounce strategy! I marked T.J. Crowder as the best answer, because it was a good explanation and one of the first. But thank you all once again!

What you've described wanting to do doesn't immediately say "use a reference to a variable" to me (as Teemu points out, sounds like you want debouncing), but answering your question about references to variables...
JavaScript doesn't have any form of references to variables (other than through closures, which might be problematic here). But you can readily do what you're talking about by just using an object and using a property on it. The property is the "variable."
Simple example:
function foo(obj) {
var counter = 0;
var timer = setInterval(function() {
console.log("foo: " + obj.property);
if (++counter === 5) {
clearInterval(timer);
}
}, 500);
}
var o = {property: "unchanged"};
// Give the "reference" to `property` to `foo`:
foo(o);
// Update it periodically while `foo` is doing its asynchronous thing
setTimeout(function() {
o.property = "update 1";
}, 1000);
setTimeout(function() {
o.property = "update 2";
}, 1700);

In JavaScript values such as integers, strings, etc. are passed by value. If you want to pass a reference, you have to pass an object into the JavaScript function. (JavaScript objects are passed by reference)
function adjustValues(referenceObject) {
referenceObject.foo = 2;
referenceObject.bar = "newValue";
}
referenceObject = {
foo: 1,
bar: "initialValue"
};
adjustValues(referenceObject);

why don't you use the setInterval function, it will do exactly what you want.
Example:
setInterval(function() {
// logic to be implemented
}, delayInMilliseconds)

How can this be accomplished?
Not with a variable. There are no "references to variables" in JS. I can see two simple solutions:
pass a getter/setter function:
function queue(getStatus) {
…
getStatus() // gets current value
…
}
var executed = false;
queue(function() { return executed; });
pass an object with a property:
function queue(status) {
…
status.executed // gets current value
…
}
var status = {executed: false};
queue(status);
I have come up with a solution that involves executing a function only once per {whatever} milliseconds. This involves a variable set to true or false, if the function has already been executed in the {whatever} milliseconds.
I cannot see the reason why this variable would need to be a parameter to the function, and be available (or even settable?) outside it. Just use a local variable inside queue.
Btw, this functionality is known as debouncing, you don't have to write this yourself. Many implementations are already available on the web, sometimes as part of larger libraries. See for example What does _.debounce do?.

Try the following example :
'use strict';
var observable = 0;
function incObservable() {
++observable;
console.log('incObservable observable: '+observable);
}
function observe() {
console.log('observe observable: '+observable);
}
var observer = setInterval(observe, 100);
setTimeout(function() {
incObservable();
setTimeout(function() {
incObservable();
setTimeout(function() {
incObservable();
}, 300);
}, 300);
}, 300);
setTimeout(function() {
// Stop obsever
clearInterval(observer);
}, 1000);
// observe observable: 0
// observe observable: 0
// incObservable observable: 1
// observe observable: 1
// observe observable: 1
// observe observable: 1
// incObservable observable: 2
// observe observable: 2
// observe observable: 2
// observe observable: 2
// incObservable observable: 3
// observe observable: 3

Related

What is better way to access this. Function.bind vs capturing variables

This is a basic question, but this impose an interesting question.
For instance,
var Foobar = function(){
this.baz = 100;
this.timer = null;
this.printLazy = function(){
this.timer = setTimeout(function(){
console.log(this.baz); //correctly bind this.
}.bind(this), 1000);
}
}
creates a traditional class that we can create instance and call printLazy as
var myBar = new Foobar();
myBar.printLazy();
Now in above code, printLazy method sets a timer and inside it, we access this.
Same thing can be achived using capturing as,
this.printLazy = function(){
var self = this; //capture this.
this.timer = setTimeout(function(){
console.log(self.baz); //correctly bind this.
}, 1000);
}
Is one of these methods are better than the other? (Considering efficiency or performance)
Can 2nd method can cause memory leaks, if its called lets say 1000 or more times in a quick succession where self would be referenced by other parts inside the function?
Is one of these methods are better than the other? (Considering efficiency or performance)
Not really. In your specific example, the version using bind creates an unnecessary function object (but JavaScript engines are very fast at doing that). But it also means that the function you're passing setTimeout doesn't close over anything, which is information the JavaScript engine might be able to use to optimize the context attached to it ("closure optimization").
But in modern environments, you'd probably use an arrow function in that situation rather than your self option:
this.printLazy = function(){
this.timer = setTimeout(() => {
console.log(this.baz);
}, 1000);
}
That will log this.baz as of when the timer fires. Another option, depending on what you need logged, would be setTimeout(console.log, 1000, this.baz). The difference is that this version will log the value this.baz has when the timer is set up, not as of when it fires. (It also relies on the fact that console.log, in most [but perhaps not all] environments, doesn't care what this is when you call it.) That's because setTimeout passes any extra arguments you give it to the function it calls when it calls it.
Can 2nd method can cause memory leaks, if its called lets say 1000 or more times in a quick succession where self would be referenced by other parts inside the function?
No. Memory leaks aren't caused by doing things quickly. They're caused by holding onto memory when you don't need it any more and not releasing it. What you're doing doesn't do that.
Had the same problem (in React) recently and found this article that shows several options. Below are 3 for your case, with the last one being the recommended option.
Option 1
Use arrow functions. But, this will still create a new function every time printLazy is called.
this.printLazy = function(){
this.timer = setTimeout(() => {
console.log(this.baz); //correctly bind this.
}, 1000);
}
Option 2
Create second function and bind it in the constructor, which still has performance drawbacks.
var Foobar = function(){
constructor() {
this.printLazyCallback = this.printLazyCallback.bind(this)
}
printLazyCallback() {
console.log(this.baz); //correctly bind this.
}
}
Option 3 (the one you should use)
Create second function as class prop arrow function
var Foobar = function(){
printLazyCallback = () => {
console.log(this.baz); //correctly bind this.
}
}

Knockout.js "visible" calling async function - not working

I've been trying to understand async, promises, etc. and I think I have a basic understanding of it, but I'm not getting the results I expect.
I have a HTML table, with the following:
<table data-bind="visible: viewPrincipal()">
viewPrincipal() is a function that should return true or false. This does work at the most basic level if viewPrincipal() just consists of return false or return true. But what I'm trying to do is call an async function to get the true or false value from there.
function viewPrincipal() {
console.log("Seeing if person is in principal group");
return IsCurrentUserMemberOfGroup("Principal Members", function (isCurrentUserInGroup) {
console.log(isCurrentUserInGroup);
return isCurrentUserInGroup;
});
}
The console.log works, and returns a true or false as I'd expect it to. But I want the parent viewPrincipal() function to return that true or false value, and all I get is "undefined".
I understand why this is happening - the IsCurrentUserMemberOfGroup() function is taking a bit of time to complete - but I don't know how to fix it. I know how to chain functions together, but when I'm trying to use something like knockout.js to determine if a table should be visible or not, I don't know how to chain.
Can anyone help?
The best way is to use an observable bool, and let your a-sync function change it's value. Let the magic of two-way-bindings do the rest.
Example:JSFIDDLE
function vm() {
this.viewPrincipal = ko.observable(false);
};
var vm = new vm();
ko.applyBindings(vm);
function fakeAsync() {
setTimeout(() => {
vm.viewPrincipal(true);
}, 1500);
}
fakeAsync();
I am a bit lost with your approach, but I'll try to help.
First, please double-think whether you really want to implement access control on the client side. Simply hiding an element if the user does not have sufficient rights is pretty dangerous, since the (possibly) sensitive content is still there in the DOM, it is still downloaded, all you do like this is not displaying it. Even a newbie hacker would find a way to display it though - if nothing else he can simply view it using the F12 tools.
Second, is that triple embedding of functions really necessary? You have an outermost function, that calls a function, which, in turn, calls the provided callback. You could clear this up by using computed observables:
function viewModel() {
var self = this;
var serverData = ko.observable(null);
this.viewPrincipal = ko.computed(function() {
var srvDataUnwrapped = serverData(); // access the inner value
if (!srvDataUnwrapped) {
return false;
}
// Do your decision logic here...
// return false by default
return false;
});
// Load the permission details from the server, this will set
// a variable that the viewPrincipal depends on, this will allow
// Knockout to use its dependency tracking magic and listen for changes.
(function() {
$.ajax(url, {
// other config
success: function (data) {
serverData(data);
}
);
})();
};
var vm = new viewModel();
and then in your view:
<table data-bind="visible: viewPrincipal">
note the lack if ()'s here, it is an observable, so Knockout will know how to use it.
If this seems overly complicated to add to your already existing code, then you could simply define an observable instead, and set the value of that inside your callback:
function viewModel() {
// other stuff ...
this.viewPrincipal = ko.observable(false);
// Call this wherever it fits your requirements, perhaps in an init function.
function checkPrincipal() {
IsCurrentUserMemberOfGroup("Principal Members", function (isCurrentUserInGroup) {
viewPrincipal(isCurrentUserInGroup);
});
};
};
With this approach, the markup would be the same as in the previous one, that is, without the parentheses:
<table data-bind="visible: viewPrincipal">
Doing it this way will simply set the inner value of an observable inside the callback you pass to IsCurrentUserMemberOfGroup, and because Knockout is able to track changes of observables, the value change will be reflected in the UI.
Hope that helps.

How can a property be assigned during object construction with a value generated asynchronously?

How can a property be assigned during object construction with a value generated asynchronously?
I'm trying to assign a property to an object during construction that needs to be retrieved via AJAX:
//define module prototype
Library.Module = function () {
this.resources = {};
for (var i = 0; i < arguments.length; i++) {
// assume that Library.require makes a request and
// then executes this callback
Library.require(arguments[i], function (resource) {
// ! the problem seems to be that 'this' is undefined
// in the scope of the callback
this.resources[resource.location] = resource;
});
}
};
I think the intention of this code is rather clear - The problem is that this appears to be undefined in the scope of the callback function.
As seen in the following article https://blog.engineyard.com/2015/mastering-this-in-javascript and following discussion in comments, a possible solution would be to store this in a variable higher in the scope to use it in the callback.
Therefore a possible solution could be :
Library.Module = function () {
var _this = this;
_this.resources = {};
for (var i = 0; i < arguments.length; i++) {
// assume that Library.require makes a request and
// then executes this callback
Library.require(arguments[i], function (resource) {
_this.resources[resource.location] = resource;
});
}
};
Useful snippet from the article cited:
Managing this in a callback
And that’s it: those are the four ways to set a function’s this value.
Those four rules are not too hard to remember, but there is a common
pitfall you should know about. I’m talking about callbacks. It’s easy
to be writing a callback and not even know it, like in setTimeout:
setTimeout(function() {
$(‘button’).addClass(‘red’);
}, 1000);
The setTimeout function accepts a callback, but since it’s not using
one of the four rules for setting context, this defaults to the global
window object. That’s fine in the example above, but becomes a bug in
code like this:
$('button').on('click', function() {
setTimeout(function() {
// Uh oh! `this` is the global object!
$(this).addClass('clicked');
}, 1000);
});
We’re expecting $(this) to refer to the button that was clicked, but
it doesn’t, since this defaults to the global window object. One way
to solve this issue is to store our desired value of this in a local
variable and then simply use that variable in a child scope:
$('button').on('click', function() {
var _this = this;
setTimeout(function() {
$(_this).addClass('clicked'); // All better
}, 1000);
});
Of course there are many ways to accomplish the same thing. You could
use .bind(), .call(), or a number of other options. Choose what works
best for each individual situation.

Javascript and prototyping procedure

I am trying to write a script that does a slide show. I can do it with functions, but I want to use the prototype method. What I am having a hard time figuring out is the procedure. Here is what I have tried to do
var displayVars = {
slide: '',
thumb: ''
}
//setup display
display = function(slide,thumb) {
displayVars.slide = $(slide);
displayVars.thumb = $(thumb);
// set slider width
}
display.prototype.play = function() {
// move slide to this location
display.hightlight();
}
display.prototype.hightlight = function() {
// add border to element
}
$(function() {
newdis = new display('.show-slide','.window-thumbs');
displayVars.timer = setTimeout(newdis.play,500);
});
If you notice in the play function I want to call the highlight method. What I really want is to run the highlight function every time the play function is called. I can't get my head to see how this can be done because "display" or "this" will not let me access the highlight function.
The problem is not with the innards of your prototype functions, but rather with the way you set up the timeout handler.
displayVars.timer = setTimeout(function() { newdis.play(); }, 500);
Then you'll be able to use this in the "play" function:
display.prototype.play = function() {
// move slide to this location
this.hightlight();
}
There's no intrinsic "membership" relationship between a function and an object of any sort. Object properties can refer to functions, but the only time that means anything is when a function call is made via the object property reference. Since you weren't calling the function, but just grabbing a reference to it to pass to "setTimeout()", there was nothing to set the value of this. By wrapping it in an anonymous function that explicitly calls "play" via the object reference, you set up this correctly.
Another way to do this is with the "bind()" function available in newer browsers:
displayVars.tinmer = setTimeout(newdis.play.bind(newdis), 500);
That will have more-or-less the same effect as the anonymous function (with some extra subtleties that don't make much difference most of the time).

Strange JavaScript behaviour, variable changing value before converter function is called

I'm passing down some JSON data from Smarty. I'm applying this to a JavaScript variable, options.
If you've seen my previous question about date formats you'll know I need to do a bit of work on the data coming in, so I've got a function called chart_convert_dates() that's called, passing in the options (well, options.data), and upon it's return setting it back again.
If you read through my code you'll notice I'm debugging the options variable, and it changes from the original before the function is called!?
If I comment out the function call, the variable is untouched, as it should be at that point.
This happens with Chrome, FF... what's going on?
{literal}
<script type="text/javascript">
$(document).ready(function() {
// set JS var, this data is coming in from smarty
var options = {/literal}{$options}{literal};
// these should both be exactly the same
debug.debug({/literal}{$options}{literal});
debug.debug(options);
// but the above outputs aren't the same! options has been modified
// by the function below... that hasn't even fired yet!? We can prove
// this by commenting out the following function call
options.data = chart_convert_dates(options.data);
// ... do something else
});
</script>
{/literal}
This is, of course, impossible.
You'll probably find that the debug.debug() function is saving a reference to the object it is provided with, rather than converting it to a string immediately. When you then view the contents of it's argument at a later time, the output will reflect the current state of the object, rather than the state it was in.
This is best explained with the following example:
var debug = {
report: function () {
// console.log(this._value);
},
debug: function (arg) {
this._value = arg; // save a reference
}
}
var options = {
foo: 1
};
debug.debug(options);
options.foo = 2;
debug.report(); // will show 2 (http://jsfiddle.net/zQFPm/)
http://jsfiddle.net/zQFPm/

Categories

Resources