After I execute a function (getAvailableLabs) in this case - I want to either execute a callback or a promise. I'm not sure which I should be executing however I can't get either to work.
Routes:
router.get('/api/content_left', function(req, res, next){
const Labs = require("../models/Labs.js");
l = new Labs("Sample Lab", "Sample Description", "Sample Category", "Sample Tech");
l.getAvailableLabs(function(){
console.log("We made it here!");
});
console.log("This is post resposnse");
Labs.js:
getAvailableLabs() {
var d = db.any('select * from labs')
.then(data => {
console.log(data[0]);
return data
})
.catch(function (error) {
console.log(error + " - Error in function");
return error;
});
}
In the above case, it logs "end of available labs" followed by "this is post response". That's what I would expect with my understanding of callbacks. However it never executes "We made it here!" and I don't understand why? My impression is if I place a function within a function - it will be executed as a callback however this does not happen. Do I need return a specific way to execute a callback?
Thank you for your help.
Your getAvailableLabs function does not accept a callback parameter. I think it'd be best to stay consistent and use promises:
getAvailableLabs() {
return db.any('select * from labs')
.then(data => {
console.log(data[0]);
return data
})
.catch(function (error) {
console.log(error + " - Error in function");
return error;
});
}
...
l.getAvailableLabs().then(data => {
console.log("We made it here!");
});
If you'd like to use a callback instead of a promise here's how I'd write getAvailableLabs:
getAvailableLabs (callback) {
db.any('select * from labs')
.then(data => {
console.log(data[0]);
if (callback) { callback(null, data); }
})
.catch(function (error) {
console.log(error + " - Error in function");
if (callback) { callback(error); }
});
}
Calling this function:
getAvailableLabs((err, data) => console.log("We made it here!");
Related
The following code is returning undefined when I attempt to execute the error, callback capability. I don't understand why the json isn't returning as the console log outputs the complete query.
Here is the invoked function that is producing the json into the log.
exports.getThem = (req) => {
var addy = req.body.email;
Picks.findOne({ 'email' : addy }, (err, theResults) => {
if (err) {
return ({ 'msg': err });
}
console.log("made the query " + JSON.stringify(theResults));
return theResults;
});
};
Above, theResults print "made the query " and a complete JSON string.
The invoking code will execute and return to Postman the following JSON without the theResults JSON.
The console.log "log this" never executes and the 2nd log prints "after the log" undefined.
{
"token" : someCrazyLookingToken
}
exports.loginUser = (req, res) => {
var theResults;
theResults = Picks.getPicks( req , ( err , thePicks) => {
console.log("log this" + JSON.stringify(thePicks));
if (!err){
console.log ("what happened" + err)
}
});
console.log("after the call " + JSON.stringify(theResults));
return res.status(200).json({ picks: thePicks, token: createToken(user) });
}
Why? Is there a timing issue I'm not waiting for in the callback?
It's not necessarily a timing issue, but perhaps a misunderstanding on your part in how callbacks work, particularly in their scope. In your code, theResults is never going to have a value.
Try setting it up like this, and read up on promises and callbacks to get a better understanding on both.
exports.loginUser = async (req, res) => {
try {
const theResults = await new Promise((resolve, reject) => {
Picks.getPicks(req, (err, thePicks) => {
if (err) {
return reject(err);
}
return resolve(thePicks);
})
});
return res.status(200).json({picks: theResults, token: createToken(user)});
} catch (err) {
//handle err
}
}
I'm having trouble understanding the output printed why executing this code :
1
2
Unhandled rejection Error: Callback was already called.
It seems like both then and catch are executed when the query is successful.
Any idea ?
Cheers
async.series([
function(callback) {
db.none(query)
.then(function () {
return callback(null, true);
})
.catch(function (err) {
return callback(err, null);
});
},
function(callback) {
db.any(query)
.then(function (data) {
console.log('1')
return callback(null, data);
})
.catch(function (err) {
console.log('2')
console.log(err);
return callback(err, null);
});
}
],
function(err, results) {
if (results && !results[1].isEmpty()) {
// do something
}
});
EDIT :
TypeError: results[1].isEmpty is not a function
It seems like the problem come from the rest of the code and was just a simple undefined function error, thanks.
But i still don't understand something : why is this error catched inside the second query instead of outside the async queries ?
I'm the author of pg-promise.
You should never use async library with pg-promise, it goes against the concept of shared/reusable connections.
Implementation with proper use of the same connection, via a task:
db.task(t => {
return t.batch([
t.none(query1),
t.any(query2)
]);
})
.then(data => {
// data[0] = null - result of the first query
// data[1] = [rows...] - result of the second query
callback(null, data); // this will work, but ill-advised
})
.catch(error => {
callback(error, null); // this will work, but ill-advised
});
See also: Chaining Queries.
However, in your case it looks like when you call the successful callback(null, data), it throws an error, which in turn results in it being caught in the following .catch section. To test this, you can change your promise handler like this:
.then(data => {
callback(null, data);
}, error => {
callback(error, null);
});
It should normally throw an error about Promise missing .catch because you threw an error while in .then and there is no corresponding .catch chained below, which you can also check through this code:
.then(data => {
callback(null, data);
}, error => {
callback(error, null);
})
.catch(error => {
// if we are here, it means our callback(null, data) threw an error
});
P.S. You really should learn to use promises properly, and avoid any callbacks altogether. I only provided an example consistent with your own, but in general, converting promises into callbacks is a very bad coding technique.
This is what happens:
callback(null, data) is called within the context of the .then();
async notices that this was the last item of the series, so it calls the final handler (still within the context of the .then());
the final handler throws an error;
because the code runs in the context of .then(), the promise implementation catches the error and calls the .catch();
this calls the callback again;
PoC:
const async = require('async');
async.series([
callback => {
Promise.resolve().then(() => {
callback(null);
}).catch(e => {
callback(e);
});
}
], err => {
throw Error();
})
Have you try to define your function externally:
function onYourFunction() {
console.log('Hi function');
}
and than do:
.then(onYourFunction) //-->(onYourFunction without parentheses )
Unfortunately i don't use pg-promise but i can advise promise
at this point i create all promises that are necessary:
function createPromise(currObj) {
return new Promise(function (resolve, reject) {
currObj.save(function (errSaving, savedObj) {
if(errSaving){
console.log("reject!");
return reject(errSaving, response);
}
console.log('currObj:' + currObj);
return resolve(savedObj);
});
});
}
and then in cascades:
var allPromiseOs = Promise.all(promise1, promise2, promise3);
I've been struggling with handling retrieval of Spotify data in an Ionic service all day, and something that was working earlier now suddenly doesn't.
I have my login script set up in a service, and it is all working fine. However, after the console.log('updateInfo() called'); method inside updateInfo, the program will skip the rest of the function, avoiding gathering the data from Spotify.
This is the entire service so far:
.factory('SpotifyService', function ($cordovaOauth, Spotify) {
var currentUser = {},
userId = '';
function login() {
console.log('login() called');
$cordovaOauth.spotify('583ac6ce144e4fcb9ae9c29bf9cad5ef', ['user-read-private', 'playlist-read-private']).then(function (result) {
window.localStorage.setItem('spotify-token', result.access_token);
Spotify.setAuthToken(result.access_token);
}, function (error) {
console.log("Error ->" + error);
});
}
function updateInfo() {
console.log('updateInfo() called');
Spotify.getCurrentUser().then(function (data) {
console.log('Gathering data');
currentUser = data;
userId = data.id;
console.log("CURRENT USER: " + userId + " - (" + currentUser + ")");
console.log('Done updating');
});
}
return {
getUser: function () {
console.log('SpotifyService.getUser() called');
var storedToken = window.localStorage.getItem('spotify-token');
if (storedToken !== null) {
console.log('Token accepted');
currentUser = updateInfo();
console.log('getUser function returns: ' + userId + " - (" + currentUser + ")");
//currentUser = Spotify.getCurrentUser();
} else {
console.log('getUser else accessed');
login();
}
return currentUser;
}
};
})
Any ideas as to why the Spotify.getCurrentUser() method won't run?
It seems like your issue is with promises. If Spotify.getCurrentUser() returns a promise you wouldn't know what the error is because you haven't defined a catch statement. You should read Promises in Angular Explained as a Cartoon for a simple and clear explanation of promises.
Revise your code to add a catch statement:
Spotify.getCurrentUser()
.then(function (data) {
...
})
.catch(function(error){
console.log(error);
});
Every time you use promises like $cordovaOauth.spotify() or Spotify.getCurrentUser() you have to define .catch block, that will help you debugging.
Add .catch block to the getCurrentUser() function call to track down your error and i would also recommend changing error callback pattern in auth function call into .catch block as well
.catch(function(error){
console.log(error);
});
I have following code in my node.js file;
GameHelperAuth.prototype.GetUserViaApi = Promise.method(function (authCookie, callback) {
// get user from API
});
GameHelperAuth.prototype.GetObjectFromCache = Promise.method(function (authCookie, callback) {
// get user from Cache
});
GameHelperAuth.prototype.GetUser = function (authCookie, callback) {
// check cache
this.GetObjectFromCache()
.then(function (result) {
if (result) {
return callback(null, result);
}
else {
// not found in cache, get it from API
// **NOT WORKING HERE - undefined error**
this.GetUserViaApi(authCookie)
.then(function (apiResult) {
return callback(null, apiResult);
}).catch(function (err) {
throw err;
});
}
})
.catch(function (err) {
throw err;
});
I would like to access my instance method from another instance method once promise is completed. But it looks like it loses it's context and cannot find function anymore. (Please see where I am calling GetUserViaApi method)
Is there any way for me to reach that method without creating new instance of my class?
As far as I can see, the simplest fix here is to just declare var self = this in the first line of .GetUser() and then use self instead of this inside the .then callback.
Alternatively if you're using Node 4+ with ES6 compatibility, use an "arrow function" as the outer .then callback that inherits the lexical this instead of contextual this:
return this.GetObjectFromCache()
.then((result) => {
if (result) {
return callback(null, result);
} else {
// not found in cache, get it from API
return this.GetUserViaApi(authCookie)
.then(function (apiResult) {
return callback(null, apiResult);
}).catch(function (err) {
throw err;
});
}
})
.catch(function (err) {
throw err;
});
NB: note the addition of the return in the first line and in the else clause, necessary to ensure that the function and that branch both correctly return a promise.
FWIW, I also think you can refactor this substantially by eliminating the repeated call to return callback(...) through a chaining .then:
GameHelperAuth.prototype.GetUser = function (authCookie, callback) {
return this.GetObjectFromCache()
.then(result => result || this.GetUserViaApi(authCookie))
.then(result => callback(null, result));
}
I've removed both .catch blocks - doing .catch(function(err) { throw err }) is a no-op - AIUI the throw would make the caller end up in their own .catch block so you might just as well let the entire promise reject anyway.
We're using the Q promise library in our node API, but allow functions to be called via callbacks.
For example:
function foo(cb) {
Q.fcall(function () {
return true;
}).then(function (result) {
return cb(null, result);
}).catch(function (err) {
return cb(err, null);
});
}
When I run my mocha unit tests, if there is an exception in the callback, it results in the the callback being called twice.
For example:
var called = 0;
foo(function (err, res) {
called++;
console.log('err: ' + err);
console.log('res: ' + res);
console.log('called: ' + called);
throw Error(throw Error from foo!');
});
This gives the following result:
err: null
res: true
called: 1
err: Error: throw Error from foo!
res: null
called: 2
One approach we found was to do the following:
function foo2(cb) {
var _result, _err;
Q.fcall(function () {
return true;
}).then(function (result) {
_result = result;
}).catch(function (err) {
_err = err;
}).finally(function () {
_.defer(cb, _err, _result);
});
}
The idea was to have one place where the callback would be called and try to prevent developer errors by enforcing the defer to clear the call stack.
With this approach, our callback is called once, and any errors (or in our case, asserts) get handled directly by the caller.
Is there a better technique we can use? I feel like this is a pretty common scenario, so I'd imagine there exists a cleaner solution...
Modify your foo function to handle both the fulfillment and the rejection in the same then call using 2 separate handlers:
function foo(cb) {
Q.fcall(function () {
return true;
}).then(function (result) {
return cb(null, result);
}, function (err) {
return cb(err, null);
});
}