How do I set an object's properties from an asynchronous function without losing the values? Someone on another SO thread said that anything that has to do with this function should be kept inside the function. However,I want to assign values from it, and assign it to an object. I'm a little new to OOP Js, so this was confusing to me.
I have this function that gets the user's location. This HTML5 function requires a callback to pass a position object into.
function getInfo()
{
navigator.geolocation.getCurrentPosition(getPos);
}
This is the function that is referenced in getCurrentPosition().
function getPos(position)
{
PositionObj.lat = position.coords.latitude;
PositionObj.lon = position.coords.longitude;
}
PositionObj:
var PositionObj =
{
lat:null,
lon:null,
returnLat: function()
{
return this.lat;
},
returnLon: function()
{
return this.lon;
}
};
When I try to access PositionObj's properties, I get null, and not the new value that was assigned by the callback. How do I go about doing this? I've tried things like making the callback an object itself, and passing the values to another function that assigns values to the object. Any help would be appreciated!
The most important question is: when are you trying to access PositionObj's properties? Since the whole thing is asynchronous, you won't see any value in lat or lon until the location is retrieved and getPos assigns it. Thus, something synchronous like:
getInfo();
console.log(PositionObj.lat);
is definitely not going to work. getInfo returns immediately and doesn't wait for the location to come in. That's a good thing: the whole idea about asynchronism is that you don't wait (block) until you get your results. Instead, you give a callback to the function and that function makes sure to call it when the results are retrieved later on. In Hollywood style: "don't call me, I call you!"
Thus, anything that relies on the actual position retrieved by getInfo needs to be in the callback. This means that you have to think and code differently: you'll need to break up your synchronous function into smaller functions which are chained up as callbacks.
In your case, you'd put that console.log(PositionObj.lat) (or anything else you want to do with the position) inside (what you called) getPos (you probably want to think of a better name for that function though).
Here's a more complete example which demonstrates the concept better. An online shop may have something like this on its checkout page:
var position = getPosition(); // using geolocation
var closestShop = getClosestShop(position); // using AJAX to a server-side script
alert("The closest shop is " + closestShop);
However, all those synchronous calls would block the script's execution and the page would "freeze". The user would probably think that his browser crashed, and that's not a great user experience.
If all these actions were asynchronous, you'd restructure it so it looks like this:
getPosition(function(position) {
getClosestShop(position, function(closestShop) {
alert("The closest shop is " + closestShop);
});
});
Here, each function accepts a callback function which it calls when the results are in. They all return immediately, allowing the script to continue execution and keep the page responsive. Of course, nothing stops you from starting another asynchronous action from within this callback, effectively chaining them up.
In fact, this last pattern is so popular that a new mechanism was created to make it more manageable: promises. The inner workings are still the same (functions accepting a callback instead of blocking synchronously) but it looks more pleasant. When you make getPosition and getClosestShop return a promise, you could write:
getPosition().then(getClosestShop).then(function(closestShop) {
alert("The closest shop is " + closestShop);
});
Related
I realise this is more of a general question, but I've read through similar answers on here but I can't find more of an overview. I'm new to callbacks and I'm trying to understand when they should be used.
The MDN web docs has this example;
function greeting(name) {
alert('Hello ' + name);
}
function processUserInput(callback) {
var name = prompt('Please enter your name.');
callback(name);
}
processUserInput(greeting);
However I'm struggling to see how this is more beneficial than the following, where I'm not passing the greeting function as a parameter?
function greeting(name) {
alert('Hello ' + name);
}
function processUserInput() {
var name = prompt('Please enter your name.');
greeting(name);
}
processUserInput();
As Javascript is async, sometimes it is difficult to handle response from non-blocking functions, for ex. if you are making an ajax call then it'll be executed asynchronously and results will be returned sometime later, by that time the main execution flow will pass the ajax code and starts executing following statements, in that case, its very difficult to catch the response to process further.
To handle those cases, callbacks comes into picture where you pass a function as the parameter to the ajax function and once the response is returned then call the callback by passing response data as a parameter to process further.
more info here http://callbackhell.com/
In simple terms you can say a callback is a way of asking a question (or requesting a task) in advance, i.e. when you're done with this do this (usually with the result). The whole point is to set aside functions that are to be done later, usually because you don't have the required inputs to do them now.
The 2 main differences between your implementation and the MDN one is that yours is harder to maintain and harder to reason about hence test.
1. Maintanance / Reusability
Imagine you're a few thousand lines of code into a code base then you're required to change what processUserInput() does. Its much easier to change or write a new callback function instead of changing the function processUserInput(). This would be evident if processUserInput was a bit more complicated. This also means the MDN one is much more useful in various scenarios unlike your implementation. You can reuse it in different situations like saying good bye, capitalizing names etc simply by writing different callbacks to plug into processUserInput().
2. Testing / Easier to reason about
The MDN implementation is much more easier to understand. Its easier to assume that the function processUserInput(greeting) will probably return a greeting than it is to assume what processUserInput() does. This makes it easier to test because you can always be sure the MDN implementation will always return the same output given an input.
Callbacks can be extremely useful depending on the circumstances; for example, when working with JavaScript for Google Chrome browser extension development, a callback can be used for intercepring web requests once it has been setup.
The purpose of a callback in general is to have the callback routine executed upon a trigger - the trigger being an event of some kind. Usually, functionality follows an interface of chained APIs. By implementing callback support, you can redirect execution flow during a stage of an operation. Callbacks are especially useful to third-party developers when dealing with someone elses library depending on what they are trying to do. Think of them like a notification system.
Functions in general taking in parameters is useful for flexibility and maintenance. If you use different functions for different things, the functions can be simply re-used over and over again to provide different functionality - whilst still preventing bloating the source code with more-or-less the same code over and over again. At the same time, if you use functions to your own library and a bug shows up, you can simply patch it for the one function and then it will be solved.
In your example, your passing a callback routine to the function you're calling - the function you're calling will call the callback function and pass the correct parameters. This is flexible because it allows you to have a callback routine called for printing the contents of the variable, and another for calculating the length of the string passed in, or another for logging it somewhere, etc. It allows you to re-use the function you setup, and have a different function called with the correct parameters without re-making the original function.
This example is not appropriate for understanding callbacks
In simple Language callbacks functions are used when we have to do some stuff after or in response of some other event or function or expression.
i.e when the parent function completes its execution then callback gets executed.
simple Example
function hungerStatus(status,cb){
return cb(status)
}
function whatToDo(status){
return status ? "order Pizza" : "lets play"
}
hungerStatus(false,whatToDo)
Another example
// global variable
var allUserData = [];
// generic logStuff function that prints to console
function logStuff (userData) {
if ( typeof userData === "string")
{
console.log(userData);
}
else if ( typeof userData === "object")
{
for (var item in userData) {
console.log(item + ": " + userData[item]);
}
}
}
// A function that takes two parameters, the last one a callback function
function getInput (options, callback) {
allUserData.push (options);
callback (options);
}
// When we call the getInput function, we pass logStuff as a parameter.
// So logStuff will be the function that will called back (or executed) inside the getInput function
getInput ({name:"Rich", speciality:"JavaScript"}, logStuff);
refer callback exaplanation
I'm sure there's an easy way to do this, but I'm having difficulty wrapping my mind around asynchronous calls and their flows. I'm trying to do a simple assignment statement in javascript, followed by setting a timer to perform operations on that object once it's been assigned. I have something along the lines of:
var info = getInfo();
$timeout(updateInfo(info), 5000);
However, I don't want the timeout to be executed until info is set initially. I've tried looking into using .then or some form of callback, but I haven't successfully determined how to do that. I'm unsure if having the parameter of info in the updateInfo call makes it so that I can't use callbacks in getInfo or what the correct flow is. I've read other articles and stack overflow responses, but couldn't find one dealing with asynchronous assignment and then using that as a paremter in a subsequent call.
getInfo and updateInfo are methods that return Highcharts graph config objects. Without copying over all the specific details:
getInfo: function() {
return {
options: {
chart: {
type: 'line'
}
}
...
}
}
updateInfo: function(info) {
// Here computations are performed on plot series data.
info.series.push(...)
}
Both getInfo and updateInfo looks pretty sync to me.
So there shouldn't be any synchronization problem.
The only thing I noticed is the wrong use of $timeout in your example.
$timeout(updateInfo(info), 5000); this way updateInfo will be called before the timeout starts and the returned value will be passed as a parameter.
In order to call updateInfo after 5 seconds you have to use anonymous function or bind function.
$timeout(function() { updateInfo(info); }, 5000);
$timeout(updateInfo.bind(null, info), 5000);
For more info about bind.
You should remember that although JavaScript does some asynchronous actions, yet the assignment to a variable is synchronous, which means that it occurs at the moment you requested for it, and won't go on to the next line until it's done.
If getInfo itself has the variable info in scope and updates it during the asynchronous call, then you shouldn't assign a value to it in the invocation of the function.
If I confused you, let me guess what you do there (and please provide the getInfo function for clarifying your question).
I'm pretty sure what getInfo does is an ajax call. So if you already use jQuery, you can simply use their ajax function:
function getInfo(){
$.ajax({
url: "/api/items"
}).done(updateInfo);
}
function updateInfo(data){
console.log ('Do something with', data);
}
getInfo();
See full documentation:
http://api.jquery.com/jquery.ajax/
I have a function that returns JSON data and I wish to access the data globally. I have tried returning the function as a variable and then returning it again.
News still currently returns undefined.
what I would like is for var News to equal the value of results.feed
var News = function (){
google.load("feeds", "1");
var foo;
function initialize() {
var feed = new google.feeds.Feed("http://www.telegraph.co.uk/news/uknews/rss");
feed.setNumEntries(10);
//console.log(feed),
feed.load(function(result) {
if (!result.error) {
console.log(result.feed);
foo = result.feed;
}
});
};
google.setOnLoadCallback(initialize);
return foo;
}();
console.log(News);
Your main problem is, that return foo; is called, before the request is finished. The JS-engine launches the Request and then goes on without caring of the result. And foo isn't filled with the result.
A typical problem with asynchronous requests.
According to the documentation load() loads the feeds. After successfully loading the feeds, a callback is called.
feed.load(function(result) {
/* result is accessible only in this scope*/
}
E.g. in order to display the data on the page, you have to call the display()-Function within the scope of the callback
feed.load(function(result) {
display(result)
}
You could (technically) assign the result to a variable:
feed.load(function(result) {
globalvar=result;
}
But then you have to maintain different states of this variable, since at one point in time it is not set, and at a later point in time it will be set.
There are different ways to deal with this:
1) Promises
or
2) MVC-Frameworks like Knockout, Backbone, https://angularjs.org/
where you have models, and events when these models are up to date.
Without knowing what web frameworks you are using (this google.* thing for instance) it's rather hard to help in any more detailed way.
However, if I'm guessing, I'd say that like most things in JavaScript this is an asynchronous operation and your function returns before the request has finished completing.
This is the big hurdle of JavaScript, it's not as... Straightforward as other languages, you often have to write callbacks and this is what you should do here.
In your feed.load it takes a function which contains a result, this looks like the callback.
feed.load(function(result) {
if(!result.error) {
// This will print out the feed (presumably an object).
console.log(result.feed);
}
}
You have to decide for yourself how best to handle this, at the very least articulate what it is you are trying to achieve rather than just asking for code.
I have a function which makes an AJAX request to a server and returns relevant information after it completes.
I have another function which manipulates some variables in its namespace based on the returned information.
Currently, I am appending a 'callback' argument to the first function, which is called when the request completes. This, however, blurs the purpose of the first function - instead of being a 'getInfo' function, it's become a 'getInfoAndDo' function.
Ideally, I'd like to call the second function (a 'do' function, which calls the first function, a 'get' function) and does its thing.
I have looked around and found jQuery methods such as .ajaxStop and .ajaxComplete, but they seem to only to work when bound to DOM elements. Is there any way to do this entirely in javascript?
e.g.
function _getEventAttendance(uid, callback) {
var attendQuery = FB.Data.query('SELECT eid,rsvp_status,start_time FROM event_member WHERE uid = {0}', uid);
FB.Data.waitOn( [attendQuery],
function (args){
callback(args[0]);
}
);
}
function logAttendance(attendance){
console.log(attendance);
}
Currently, I am doing:
_getEventAttendance(123456789, logAttendance);
which seems ridiculous to me.
Is there a way to write the code such that I can change the code snippet inside _getEventAttendance / remove the callback argument:
FB.Data.waitOn( [attendQuery],
function (args){
return args[0];
}
);
and then make calls that are equivalently as simple as :
logAttendance.ajaxComplete(_getEventAttendance(123456789));
(I'm just making up the syntax for this, I have no idea how it's supposed to be written.)
$.when(<AJAX Request>).then(function(response){...});
Optionally use $.pipe() to filter response first.
var plane;
$.getJSON(sTailFileName, function(plane) {
$('#upTailNum').html(plane.tailNum + ' ' + plane.airplaneType);
document.title="Load " + plane.tailNum;
.... goes on for 300+ statements ....
});
and it works fine. However, what I want to do is something like:
var plane;
$.getJSON(sTailFileName, function(plane) {});
$('#upTailNum').html(plane.tailNum + ' ' + plane.airplaneType);
document.title="Load " + plane.tailNum;
but that gives me a "plane undefined" message. I need to get at plane from outside the scope of the getJSON -- or at least want to. I've tried many things including $.proxy and through closures (which I don't yet really understand), but with no success thus far.
This is my first effort in Javascript/jQuery. I'm attempting to replace an old DOS program I originally wrote back in 1988. See http://terryliittschwager.com/WB/wbjs.html for details.
Any help will be greatly appreciated!
Terry Liittschwager
Your callback function to getJSON gets the plane value but doesn't do anything with it; so, when you do plane.tailNum, plane is still undefined because it was never assigned a value. Also, the getJSON call is asynchronous so you can't just do this:
$.getJSON(sTailFileName, function(x) { plane = x; });
because the plane = x will not have been executed (unless you get very lucky with the timing) when you try to access plane.tailNum.
You can replace the getJSON call with a synchronous $.ajax call and assign the JSON blob to plane in the success callback or keep doing things the first way. You can always put your "goes on for 300+ statements" in a separate named function, say, three_hundred_lines and refer to that by name:
function three_hundred_lines(plane) { /* ... */ }
$.getJSON(sTailFileName, three_hundred_lines);
if you don't want to inline a big pile of code.
The thing with AJAX calls is that they're asynchronous. You can access the returned value within the callback function because the callback function happens once the data is returned.
$.getJSON(); just fires off the request and returns immediately. Any code that immediately follows it will be executed before the json data returns.
The problem is that $.getJSON is an asyncronous method ie, the line $.getJSON(sTailFileName...) sends off the request but doesn't wait around for the result to be returned before continuing to the next line. The function that is supplied to $.getJSON is called once a response is recieved, which is almost certainly after the rest of the program has executed.
You shouldn't attempt to work around this. The callback function is the correct place to handle the response.
You are used to programming synchronously. You need to wrap any logic that uses the plane object in a function, and invoke that function from your getJSON callback. Something like this:
$.getJSON(sTailFileName, function(plane) {
// pass "plane" along to some other function that does the work
doStuff(plane);
});
The reason you are sending a function as an argument to getJSON is because you don't know when the response will be received.
Although I was born in 1988 when you were writing DOS programs, so if you want me to get off your lawn, I'm fine with that ;-)
-tjw