I have this variable declared at global scope:
var wait;
then, inside of an event listener, I assign a function to this variable, then attach a callback function: (I am using Dojo, via the ArcGIS Javascript API)
wait = doThis();
wait.addCallback(function (){
doNextThing();
});
doThis removes some layers from a map:
doThis(){
var layer = map.getLayer("mapLayer");
if (layer) {
map.removeLayer(layer);
}
..but when I run it, I get an error saying 'wait' is undefined...
I have similar syntax elsewhere in my code that works...is it because I am assigned the callback within an event listener? If so, is there a workaround? I really need doThis() to be completed before doNextThing() begins.
In JavaScript function always returns value and if you skip return keyword inside function then it returns undefined automatically. And in your doThis code there is no return statement. This is why wait gets undefined and fails on next step.
What should be returned? From shown example we can only deduce that object returned from doThis() offers addCallback function. Since ArcGIS is built upon Dojo Toolkit it is probably the Deferred object. What returns Deferred is open question having no other clues from your example.
Related
I have a class that I use to load external resources via an XMLHttpRequest (this is for WebGL) so I'm loading models, shaders etc. My plan was to put a loading display up whilst it did all these requests and then when it's finally complete I want it to run a callback function from the original function that created it. However, I'm getting strange results when I try to run that call back (such as it has no access of any of the objects within the class that did the loading).
I can get around this problem by passing "this" into the loading class and then doing
self = this;
promise(self.callback());
but I'd much rather specify the function that I want it to callback to after its done the loading. Does anyone know if this can be done? My code looks like this:
Main Class
this.loadingClass = new LoadingClass(this.LoadingComplete, resources);
Main.prototype.LoadingComplete = function()
{
// Returns undefined if i specify the callback function instead of just "this"
console.log(this.loadingClass.anyOfTheMembersOfThisClass);
}
Loading Class
LoadingClass = function(callback, resources) {
..
Promise.all(resources).then(function(loadedResources)
{
..
callback();
});
}
When you pass the function object as
(this.LoadingComplete, resources)
the object to which it was bound, will not be passed. So, only the function object LoadingComplete is passed to LoadingClass and when it is invoked as
callback()
the this value will be undefined (in strict mode).
To fix this,
you need to bind the this object, like this
new LoadingClass(this.LoadingComplete.bind(this), resources)
if your environment supports ES2015's Arrow functions
new LoadingClass(() => this.LoadingComplete(), resources);
In both these cases, when the LoadingComplete is invoked from LoadingClass, the this will be retained.
You are detouching callback (read about "this") function from the root object, so of course it loses context. Specify bindingContext explicitly with Function.prototype.bind method:
this.loadingClass = new LoadingClass(this.LoadingComplete.bind(this), resources);
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
When i was reading some code of jquery then i found this in one of their widgets
option: {
_page: this._getPage,
_panelInner: this._getPanelInner()
},
_getPage : function(){ //code goes here that returns something..},
_getPanelInner : function(){ //code goes here that returns something..}
I wanna know how's the first this._getPage function is being called without parenthesis. And if functions can be called like this then why the next function _getPanelInner is being called with parenthesis..?
_panelInner will hold the value returned by the _getPanelInner function while _page will hold a reference to the _getPage function. This means that the function would be able to be called in one of the following ways:
option._page()
this._getPage()
Both of these function calls would execute the same function but that function is not called automatically (according to the code that is displayed).
It's not getting called, it's only having a reference to the function so later you can do:
option._page();
Im trying to add an event listener to a object for example:
this.startLoading = function(){
this.a.addEventListener("complete", this.loadingHandler()); this gives me an error
},
this.loadingHandler = function(){
console.log("im doing something")
}
ERROR: "Uncaught Error: addListener only takes instances of
Function. The listener for event "complete" is "undefined"
However if I put the loadingHandler() function inside the scope it works, for example:
this.startLoading = function(){
var loadingHandler = function(){...}
this.a.addEventListener("complete", loadingHandler()); // this works
},
Im not sure what instances of a function means in that regard?
When you put () after a reference to a function, that means to call the function, and the value of the expression is whatever the function returns.
Your second example, that you say works, actually will not work, and you'll get the same error if the "startLoading" function is called.
Because you probably need to retain the proper context (this), what you probably need is
this.a.addEventListener("complete", this.loadingHandler.bind(this));
The .bind() method returns a function (exactly what addEventListener requires) that in turn will invoke your function such that this has the value requested.
so I've been messing around with some Jquery Ajax promises/deffers etc... and i've come across something I don't completely understand, not strictly related to the Jquery Ajax.
I have always declared and called functions like so:
function foo1() { //sets function
alert('foo1');
}
foo1(); //calls function
But it seems the more I see different code a lot of people are declaring functions like the following, I just copied and pasted an example I saw so I would't miss anything:
var promise = $.ajax({
url: "/myServerScript"
});
promise.done(myStopAnimationFunction);
I understand what the above does, just an example.
The question is, is it better to assign functions to variables? What are the pros/cons, and in what situations is this way used?
At what point in this code is the actual function called. Does
promise.done(myStopAnimationFunction);
call both the ajax function, and then the callback, or just the callback?
Thanks
In your example, you're assigning your promise variable to what $.ajax returns (which is a jqXHR object)
var promise = $.ajax({
url: "/myServerScript"
});
Your then saying that once it's done, you want to call myStopAnimationFunction. Because $.ajax is async by default, the browser will skip right over this and only call your myStopAnimationFunction when the request is complete.
promise.done(myStopAnimationFunction);
Now, with your myStopAnimationFunction; you could always just do the following:
promise.done(function(){
$('.loader').hide();
});
but if you have code which you'll be using a lot, put it in a function so you don't need to repeat yourself (see DRY) - this has nothing to do with jQuery, however.
Your example is exactly the same as doing:
$.ajax({
url: "/myServerScript"
}).done(function(){
$('.loader').hide();
});
Those are two very different things! The first one is a function declaration. The second one is a function invocation, and what is assigned to the promise variable is the value returned by the function you're calling ($.ajax).
In any case, it is possible to assign functions to variables too (but I'm not sure if that's what you're really asking – if it is, this is a duplicate of var functionName = function() {} vs function functionName() {}).
Does promise.done(myStopAnimationFunction);
call both the ajax function, and then the callback, or just the callback?
Neither. That line is a call to done on the promise object, to register a callback to be called when the ajax response arrives. At that point you call done, the ajax request may have already fired, and the response even might already be available (if that's the case, the callback will be called immediately).