I am trying to write a function that returns an object representing the position of the device: I have tried:
function getDevicePosition () {
var positionObject;
if (isDeviceReady) {
navigator.geolocation.getCurrentPosition(function (position) {
positionObject = position;
console.log('location updated');
console.log(positionObject.coords.longitude);//1. works
}, function (err) {
console.log('Failed to get device position' + err);
return null;
});
} else {
warnUser();
return null;
}
console.log(positionObject.coords.longitude);//2. doesnt work as positionObject is null.
return positionObject;
}
Notice that I have added comments marking statement 1 and statement 2. If I initialized position object in statement 1. Why is it undefined in statement 2?
Because getCurrentPosition is an asynchronous method. The line marked as 2 will run before the callback function gets a chance to execute, so positionObject will still be undefined.
You need to move all code that depends on positionObject inside the callback to getCurrentPosition.
The call to navigator.geolocation.getCurrentPosition() is asynchronous, so the execution of the rest of the function does not wait until it is finished.
So your function is at execution basically reduced to this:
function getDevicePosition () {
var positionObject;
if (isDeviceReady) {
// trigger some asynch function ...
} else {
warnUser();
return null;
}
console.log(positionObject.coords.longitude);
return positionObject;
}
From this code it should be pretty obvious, that at the point, your code reaches the console.log() your positionObject is not set, thus resulting in the error.
EDIT
With respect to your comment. The general design principle for such tasks is as follows:
// original function (triggered by a button or whatever)
function trigger() {
// do some calculations before
// trigger the position-retrival
navigator.geolocation.getCurrentPosition(function (position) {
// get the position
// ...
// call the handling function
doStuff( position );
});
}
// the function to do stuff based on the position
function doStuff( position ) {
// ...
}
Related
Is it possible to call a function in JavaScript that calls itself again, and after it calls itself again, finally runs the initial callback function?
I will explain what I mean in code...
//on page load
getProviderNextAppointment(null, function(nextAppointment) {
otherFunction(); //<----- how can I always end up back here, no matter what?
});
//getProviderNextAppointment function
function getProviderNextAppointment(startDate, callback) {
getNextAppointment('provider', startDate, function(data) {
//if provider has schedule
if(!$.isEmptyObject(data.AllProviders)) {
//set provider params
//nextAppointment = data.x
//callback
if(typeof callback === 'function') {
return callback(nextAppointment); //callback from call on page load
}
} else {
if(data.ErrorCode !== 'StartDateTooFarInFuture') {
/*---------->
* this is where we this function calls itself again;
* but when it hits the callback above (provider
* has schedule), or when it hits the callback
* below (last group of appointments), it
* should run the initial callback to
* execute otherFunction()
<----------*/
getProvidersNextAppointment(data.LatestDate);
} else { //hit last group of appointments
if(typeof callback === 'function') {
return callback(null); //callback from call on page load
}
}
}
});
}
I did not include getNextAppointment() function, because it is irrelevant to the question. Just know that it is calling an API that is returning the appointment information, as well as a LatestDate property that we are using as the startDate for the next API call. We are also looking for a response for the ErrorCode property that says it's the end of the results, so that we are not looping forever.
If you need to keep a reference to the initial callback function, then you could just pass it on via the recursive call.
Change the recursive call from this:
getProvidersNextAppointment(data.LatestDate);
to:
getProvidersNextAppointment(data.LatestDate, callback);
Now the nested function context will have a reference to the original callback function, and this could in theory cascade further down the recursion tree until the callback function is finally executed.
I'm having a synchronization and loading issues with some JS modules when the program starts. This error only shows up once at the beginning and then everything works, so it is an obvious sync problem.
The code:
//pyramid of doom
function initGame(){
initWorld(function(){
initPlayer(function(){
initBots(function(){
console.log("Game Loaded!");
update();
})
})
});
}
function initWorld(callback){
world.init(worldParams);
callback&&callback();
}
function initPlayer(callback){
player.init(scene,playerParams,world.getPhysicModel());
callback&&callback();
}
function initBots(callback){
bots.init(scene,botsParams,world.getPhysicModel());
callback&&callback();
}
function update() {
world.update(1/60);
player.update();
bots.update();
}
initGame();
The following is the error I'm getting.
Bots.js:112 Uncaught TypeError: Cannot read property 'mixer' of undefined
at Bots.update (Bots.js:112)
at update (Final.html:160)
What am I doing wrong? How can I synchronize the execution of the init functions?
(What I think that is going on is that the execution of initBots doesn't reach it end before the udpdate function starts to run.)
You can find the Bots.js module in my repository at ( 1 )
In bots.init you execute new THREE.ColladaLoader().load which looks to be asynchronous.
In its callback, you fill your _bots array (self._bots[modelLoaded] = bot;).
However, you execute bots.init() and do not wait for these asynchronous calls to complete before executing the initBots function callback. In the case of initGame execution, this callback executes update(), which in turn executes bots.update(), which tries to access this._bots[i].mixer with i index up to this._botsParams.length, i.e. a pre-defined value that does not account for how many items have been actually filled in _bots array.
Hence your error message: the array has no items yet at some indices, and trying to read a property on undefined throws an error.
Conclusion: common asynchronous issue.
You need to be passing the callbacks into the init functions. Guessing from a brief look at your bots code, they are not expecting to receive callbacks so you might be in for a rebuild.
You can't tell from the outside of an async function if it is done yet!
Equivalent to what you are doing:
let result = undefined
function takeTime () {
setTimeout(function() {
result = 'hello!'
}, 100)
}
function callback () {
console.log(result)
}
function run (callback) {
takeTime()
callback && callback()
}
run(callback) // undefined! takeTime has not finished yet
What you need to be doing:
let result = undefined
function takeTime (callback) {
setTimeout(function() {
result = 'hello!'
callback()
}, 100)
}
function callback () {
console.log(result)
}
function run (callback) {
callback && takeTime(callback)
}
run(callback) // 'hello!', the callback was only called once the takeTime function completed
I have share variable between javascript function which is asynchronous. One of them is main thread and another is event based. I want to return value when event is completed.
This is the code:
completeExecution = false; // Shared Variable (Global Variable)
indexDBdata = {}; // Shared Variable (Global Variable)
function getPermission(key) {
var permission_data={};
if(exist_in_local) {
indexdbConnection.getRecordByKey('userPermission',permitKey,function(data){
indexDBdata=data; // Before its complete function return value
});
} else {
// make ajax call & its working fine
}
return permission_data;
}
//get Data from IndexedDB
getRecordByKey:function(tableName,key,readRecords){
if(isEmptyOrNull(readRecords)){
console.log("callback function should not be empty");
return;
}
if(isEmptyOrNull(tableName)){
console.log("table name should not be empty");
return;
}
var returnObj={};
var isSuccessfull=false;
if(this.dbObject.objectStoreNames.contains(tableName)){
var transaction=this.dbObject.transaction(tableName);
var objectStore = transaction.objectStore(tableName);
objectStore.get(key).onsuccess = function(event) {
returnObj=event.target.result;
};
**//Return object after this events compelte**
transaction.oncomplete = function(evt) {
completeExecution=true;
indexDBdata=returnObj;
readRecords(returnObj);
};
transaction.onerror = function(evt) {
completeExecution=true;
indexDBdata={status:'404'};
readRecords("Table Not found");
};
} else {
completeExecution=true;
indexDBdata={status:'404'};
readRecords("Table Not found");
}
}
Problem is while retrieving data from indexedDB it always returns {} (empty object). I want to synchronised event thread and main thread or wait for event to be completed. I don't want to directly manipulate DOM on callbacks I have to return value.
If you have solution to above problem or any other trick then please help me.
Thanks in advance.
I don't find the question very clear, but if I understand it, then you need to learn more about writing asynchronous javascript. In general, functions that call callback functions are void (they return an undefined value). If you want to use the results of two callback functions together, then you will want to chain them so that upon the completion of the first function, which calls its callback function, the callback function then calls the second function which then calls the second callback. So there are four function calls involved. You will want to place the processing logic within the context of the successive callback function, instead of continuing the logic outside of the function and trying to use its return value.
In other words, instead of trying to do this:
function a() {}
function b() {}
var aresult = a();
var bresult = b(aresult);
// processing of both a and b
You would want to try and do something like following:
function a(acallback) {
acallback(...);
}
function b(bcallback) {
bcallback(...);
}
a(function(...) {
b(function(...) {
// all processing of both a and b
});
});
i have group of bind's, which gets trigger inside a function from before and after the code. like following:
function global() {
before(); // call all before binds here
//... mainFunction code...
after(); // call all after binds here
}
if one of functions inside before(); callback wants to exit or stop the global() from running further, how can i stop it, without checking the return values?
The only way to achieve this without checking the value returned, is to raise an exception by throwing an error.
function before() {
throw new Error('Ending execution');
}
function after() {
console.log('Have you met Ted?');
}
function global() {
before();
// never reaches here
after();
}
global(); // Error: Ending execution
console.log('foo'); // not executed
If you have global invoked somewhere and want any code following it's invocation to continue being executed, you'll need to wrap it with a try..catch, for example
function global() {
try {
before();
// never reaches here
after();
} catch (e) {
console.log(e); // log error. Leave this block empty for no action
}
}
global(); // Error logged
console.log('bar'); // still executed
Below shown is js code which makes call to the native functions in iOS and Android, this function is called from another js method.Since the js calls to this function is asynchronous.we could not return any values in iOS.but in Android we could return the values without any issue.In iOS control dosent wait until i get the response.Actually we are not suppose to modify this function call otherwise we can pass a callback method from the caller function.Please help me to solve this issue
VestaPhoneBridge.IsAvailable = function(featureName)
{
if(isAndroid()) {
if(typeof VestaJavascriptInterface !== 'undefined')
{
return VestaJavascriptInterface.isAvailable(featureName);
}
return false;
}
else {
bridge.callHandler('initiateIsAvailableFunction',featureName,function(response) {
return response;
})
}
};
I assume you're talking about this line.
bridge.callHandler('initiateIsAvailableFunction',featureName,function(response) {
return response;
})
The problem will most likely be your return. The anonymous function you are passing as a callback will be called whenever the async request is finished. This means that it will be called by something inside the callHandler code path.
Your function is then returning to that function, and not the VestaPhoneBridge.IsAvailable function. Your callback should set values, and perform changes instead of returning a value.
Example
function Foo(callback) {
callback(); // 42 is returned here, but not assigned to anything!
}
function Bar() {
var baz = Foo(function() {
// You want to return 42. But here you are in a totally different function
// scope! You are in the anonymous function's scope, not Bar, so you are not
// returning anything to the caller of Bar().
return 42;
}
alert(baz); // Foo doesn't return anything, so this is undefined!
}
alert(Bar()); // This is also undefined, nothing was returned.