Redis is outputting true instead of the desired value - javascript

I have nodejs running and I want to call this function:
function name(id) {
var x = rclient.get(id, function(err, reply) {
return reply;
});
return x;
}
however when I try to get the output of the function with console.log(name(1)) the output is true, instead of the value stored on the redis server. this seems like a simple thing to fix, however, it has me stumped.

Well you're using callbacks so the return value inside your callback function won't be returned to x.
Try this (depending on your redis client, I've assumed you use node-redis):
function name(id) {
return new Promise((resolve, reject) => {
rclient.get(id, function (err, reply) {
if (err) {
return reject(err);
}
resolve(reply);
});
});
}
// call with
name(1).then((value) => console.log(value)).catch((err) => console.log(err));
// better yet (inside async function)
async main() {
const value = await name(1);
}
Or, do yourself a favour and use handy-redis (https://www.npmjs.com/package/handy-redis):
async function name(id) {
return rclient.get(id);
}
// call with the same as above
Essentially, you're getting slightly confused with async/sync calls. The fact x resolves to true is likely the implementation of the .get method, and not the callback.
instead of the value stored on the redis server. this seems like a simple thing to fix, however, it has me stumped.
I felt like you when I first started with Node.js, it's odd compared to most languages, however, you'll soon find it more natural (especially with async/await syntax)

Related

How is Node's crypto.pbkdf2() supposed to work?

I've read the documentation many times for the Node crypto module's pbkdf2() function. A question I asked previously was collapsed without much thought - so let me say this: I think that I have a lack of understanding about the callback - but I have read many resources trying to truly understand it - YDKJS Async, MDN, "Learning JavaScript" by O'Reilly.
I have a console.log statement within an else clause in the callback that is logging appropriatey, so I'm certain that the callback is being executed, although my debugging program (in VSCode) isn't halting execution.
I tried two different things, as seen in the code below: one was to declare a variable and change its value to derivedKey.toString('hex') within the else clause, and the other was to return the the derivedKey.toString('hex'). Neither worked.
I tried chaining a then clause, but crypto.pbkdf2 returns void and "property 'then' does not exist on type 'void'".
Here is the written method:
private static async hashPassword(password:string, salt:string):Promise<string> {
var hashedPassword;
const iterations = 50000;
const keylen = 64;
const digest = 'sha512';
const possibleReturnedValue = await crypto.pbkdf2(password, salt, iterations, keylen, digest, (err, derivedKey) => {
if (err) {throw err;}
else {
console.log(derivedKey.toString('hex'));
console.log("Hey now");
hashedPassword = derivedKey.toString('hex');
return derivedKey.toString('hex');
}
})
return hashedPassword;
}
What it really comes down to is this: I don't know how to get the derivedKey.toString('hex') value out of a function that returns 'void' with the callback.
Your problem is that the crypto.pbkdf2 function is a bit old, and does not work with promises but using callbacks. So in order to use this function in modern asynchronous code it will be necessary to wrap that function in a Promise object.
The key idea is to call the resolve and reject function given by the promise's constructor in the callback.
Refactored to return a promise, your function will look like this:
function hashPassword(password:string, salt:string):Promise<string> {
return new Promise((resolve, reject) => {
const iterations = 50000;
const keylen = 64;
const digest = 'sha512';
crypto.pbkdf2(password, salt, iterations, keylen, digest, (err, key) => {
if (err) {
reject(err);
} else {
resolve(key.toString('hex'));
}
})
});
}

Can't promisify callback based function

I want to use the library astro-js where a typical call in their docs looks like this:
const aztroJs = require("aztro-js");
//Get all horoscope i.e. today's, yesterday's and tomorrow's horoscope
aztroJs.getAllHoroscope(sign, function(res) {
console.log(res);
});
For several reasons, I would like to use it using async/await style and leverage try/catch. So I tried promisify like this:
const aztroJs = require("aztro-js");
const {promisify} = require('util');
const getAllHoroscopeAsync = promisify(aztroJs.getAllHoroscope);
async function handle() {
let result, sign = 'libra';
try {
result = await getAllHoroscopeAsync(sign);
}
catch (err) {
console.log(err);
}
console.log("Result: " + result);
}
However, when I log result it comes as undefined. I know the call worked since the library is automatically logging a response via console.log and I see a proper response in the logs.
How can I "await" on this call? (even by other means if this one is not "promisifyable")
util.promisify() expects the callback function to accept two arguments, the first is an error that must be null when there is no error and non-null when there is an error and the second is the value (if no error). It will only properly promisify a function if the callback follows that specific rule.
To work around that, you will have to manually promisify your function.
// manually promisify
aztroJs.getAllHoroscopePromise = function(sign) {
return new Promise(resolve => {
aztroJs.getAllHoroscope(sign, function(data) {
resolve(data);
});
});
};
// usage
aztroJs.getAllHoroscopePromise(sign).then(results => {
console.log(results);
});
Note, it's unusual for an asynchronous function that returns data not to have a means of returning errors so the aztroJs.getAllHoroscope() interface seems a little suspect in that regard.
In fact, if you look at the code for this function, you can see that it is making a network request using the request() library and then trying to throw in the async callback when errors. That's a completely flawed design since you (as the caller) can't catch exceptions thrown asynchronously. So, this package has no reasonable way of communicating back errors. It is designed poorly.
Try custom promisified function
aztroJs.getAllHoroscope[util.promisify.custom] = (sign) => {
return new Promise((resolve, reject) => {
aztroJs.getAllHoroscope(sign, resolve);
});
};
const getAllHoroscopeAsync = util.promisify(aztroJs.getAllHoroscope);
You could change your getAllHoroscopeAsync to a promise function
Example:
const getAllHoroscopeAsync = (sign) =>
new Promise(resolve =>
aztroJs.getAllHoroscope(sign, (res) => resolve(res)));

Return value from a mongodb query from nodejs

EDIT
OK I read here."You can't usefully return with asynchronous functions. You'll have to work with the result within the callback. This is due to the nature of asynchronous programming: "exit immediately, setting up a callback function to be called sometime in the future. And, at least with the current standard of ECMAScript 5, you can't get around this. As JavaScript is single-threaded, any attempt to wait for the callback will only lock up the single thread, keeping the callback and the return user forever pending in the event queue."
Is this still the case today?
ORIGINAL QUESTION
I have a problem accessing my variable outside the function in my node.js application.
const url = "mongodb://localhost:27017/";
getAllSampleTypes();
// I would like to have the variable "requested" accessible here
function getAllSampleTypes() {
MongoClient.connect(url, function (err, db) {
var dbo = db.db("myDb");
dbo.collection("data").distinct("sample_type", {}, (function (err, requested) {
// variable "requested" is accessible here
})
);
});
}
I tried with async/await but I still have the same problem.
function getTypes() {
MongoClient.connect(url, async function (err, db) {
let dbo = db.db("myDb");
return await dbo.collection("data").distinct("sample_type", {});
});
}
console.log(getTypes()); //Promise { undefined }
I don't think you are going to be able to achieve what you are looking for. Async await only works once you are in scope of an async function. Your top level calls are not inside an async function so you are forced to handle the returned Promise or callback.
e.g. getAllSampleTypes().then(function(response){});
Here are a couple of samples that are similar to what you want, but either way, the top level call into an async function will have to handle the response as a Promise.
const url = "mongodb://localhost:27017/";
getAllSampleTypes().then(function(sample_types){
// Do something here.
});
async function getAllSampleTypes() {
var db = await mongo.connect(url);
var dbo = db.db("myDb");
return await dbo.collection("data").distinct("sample_type", {});
}
It's important to understand that async await really isn't anything magical, behind the scenes it's translated to Promises really. That's why your top level call into an async function can handle the response with a .then(). It's just really much cleaner to read. The code above would roughly get translated and executed as:
const url = "mongodb://localhost:27017/";
getAllSampleTypes().then(function(sample_types){
// Do something here.
});
function getAllSampleTypes() {
return new Promise(function(resolve, reject){
mongo.connect(url).then(function(db){
var dbo = db.db("myDb");
dbo.collection("data").distinct("sample_type", {}).then(function(results) {
resolve(results);
});
});
});
}
getTypes doesn't return anything. You've gotta pass it up
If you're gonna use async/await try something like
async function getTypes() {
const db = MongoClient.connect(url);
const dbo = db.db("myDb");
return await dbo.collection("data").distinct("sample_type", {});
}
console.log(await getTypes());
These might be helpful:
How can I use asyn-await with mongoclient and how-to-use-mongodb-with-promises-in-node-js
Also, you should probably close the connection with db.close() somewhere

Using callback functions inside sagas

Ok, so I've just spent a day figuring out how to use callback-functions within sagas. (Please be nice, I'm just learning this saga-stuff)
My initial problem:
I get an xml-response from the server and before going into my reducer I want to parse it into a js-object. Therefore I use xml2js.
Calling this xml2js library works with a callback:
parseString(xmlInput, (err, jsResult) => {
// here I'd like to put() my success-event, however that's not possible in this scope
})
After reading a lot about eventChannels, I've come up with this solution:
My Channel-Function:
function parseXMLAsyncronously (input) {
return eventChannel(emitter => {
parseString(input, (err, result) => {
emitter(result)
emitter(END)
})
return () => {
emitter(END)
}
})
}
Using it inside the saga:
const parsedJSObject = yield call(parseXMLAsyncronously, xmlFromServer)
const result = yield take(parsedJSObject)
The problem that I'm encountering now is that apparently even while using a callback-structure, the parseString-function is still executed synchronously. So when I get to my yield-line, the parsing has already been done and I can wait forever because nothing will happen anymore.
What's working is to make the parsing asynchronously, by replacing
parseString(input, (err, result) => {...}
with
const parser = new Parser({async: true})
parser.parseString(input, (err, result) => {...}
So basically I'm making an already blocking function unblocking just to block (yield) it again and then wait for it to finish.
My question is now pretty simple: Is there maybe a smarter way?
Why not just use the cps effect?
try {
const result = yield cps(parseString, input)
} catch (err) {
// deal with error
}

Make javascript function with callback/promise implementation to always return a promise

I'm trying to have an async authentication handler which can have an implementation with a callback or promises. The scope is to wrap this function in order to always return a promise, so I can use it further callback/promise agnostic.
I would be most grateful if someone could provide some help with these scenarios, one of the examples is real life.
What if the function is something like :
function getData(id, callback) {
var deferred = Q.defer();
apiCall('/path/to/id', function (err, data) {
if (err) deferred.reject(new Error(err));
//do something with data
deferred.resolve(processedData);
}
deferred.promise.nodeify(callback);
return deferred.promise;
}
and I want to use the .fromCallback in this manner
function myProcessedDataFunction(id) {
return Promise.fromCallback(function (callback) {
return getData(id, callback);
}, {multiArgs: true});
}
Will this work ? Will myProcessedDataFunction return a correct promise ?
A real world example is:
I have an authentication handler which might or might not be implemented with a callback function, and at the same time could be implemented using promises; or it might return a true/false value;
function authHandlerImplementation1(username, password) {
return (username === 'validUsername' && password === 'validPassword');
}
function authHandlerImplementation2(username, password, callback) {
apiCall('/path/to/authorization', function (err, result) {
if (err) return callback(err, null);
callback(null, result);
});
}
function authHandlerImplementation3(username, password) {
return new Promise(function (reject, resolve) {
apiCall('/path/to/authorization', function (err, result) {
if (err) return reject(err);
resove(result);
});
});
}
function authHandlerImplementation4(username, password, callback) {
var deferred = Q.defer();
apiCall('/path/to/id', function (err, data) {
if (err) deferred.reject(new Error(err));
//do something with data
deferred.resolve(processedData);
}
deferred.promise.nodeify(callback);
return deferred.promise;
}
I will try a bluebird implementation for 5th one.
function authHandlerImplementation5(username, password, callback) {
return apiCall('/path/to/id', callback).asCallback(callback); // I hope this is the right way to do it (correct me if I'm wrong, please)
}
and my checkAuth function uses the authHandler Implementation and wants to be callback/promise agnostic.
function checkAuth(username, password) {
var self = this;
return Promise.fromCallback(function(callback) {
return self.authHandler(username, password, callback);
}, {multiArgs: true});
}
In case the authHandlerImplementation does not use callbacks (just returns a value) (implementation1), the checkAuth hangs, nothing happens, my tests fail.
Is there any Bluebird method that can wrap any kind of authHandler Implementation into a promise (be it simple return, callback or promise implementation)?
No, Bluebird has no such utility. Supporting both callbacks and promises is nice if you provide them as an API, but not when you need to consume an API - distinguishing whether the method takes callbacks or returns promises or both is not possible from outside, and writing code that figures it out dynamically (on every call) might be possible but awkward.
Bluebird does have a utility that wraps function which might return, throw or return a promise, it's called Promise.method (and there's also Promise.try which immediately invokes it).
I would recommend to force your callers to use promises if they want to pass an asynchronous auth-handler. If they only have a callback-based one, they still can wrap it in Promise.promisify themselves before making it available to you.
I tried some stuff around and I've managed to make it work. I will provide detailed information of the methods I've tried, below. The scenario is for a json-rpc 2.0 server implementation which receives an authHandler function implementation for checking the validity of the provided credentials in a request.
Update:
Using Promise.method on the authHandler var promisifiedAuthHandler = Promise.method(self.authHandler); works for the synchronous implementation of the authHandler.
Fails for the callback implementation.
Using Promise.promisify on the authHandler wrapped in the Promise.method works for the callback implementation var promisifiedAuthHandler = Promise.promisify(Promise.method(self.authHandler));.
Fails for the synchronous implementation.
Providing a callback for the authHandler (even if it does not use it in the implementation) works for all methods. It goes like this (writing for a general case, and this is part of a module written using ES5-Class node module):
function _checkAuth(req) {
var self = this;
var credentials = self._getCredentials(req);
var promisifiedAuthHandler = Promise.method(self.authHandler); // for the sync implementation
switch (authType) {
// general case, let's say, there are several types
// will just write one as an example.
case Authorization.WHATEVERTYPE:
return promisifiedAuthHandler(credentials, function callback(err, result) {
if (err) return Promise.reject(err);
return Promise.resolve(result);
}
}
}
and the server.enableCookie/JWT/BasicAuth handler can be implemented in the three ways mentioned: sync/callback/promise; As follows:
server.enableCookieAuth(function (cookie) {
return (cookie === validCookieValue);
});
server.enableCookieAuth(function (cookie, callback) {
apiCall('path/to/auth', function(err, result) {
// apiCall could have a promise implementation, as well, and could
// be used with .then/.catch, but this is not that important here, since we care
// about the handler implementation)
if (err) return callback(err, null);
callback(null, result); // can be returned
}
});
server.enableCookieAuth(function (cookie) {
// let's write the apiCall with promise handling, since we mentioned it above
return apiCall('path/to/auth').then(function (result) {
return Promise.resolve(result);
}).catch(function (err) {
return Promise.reject(err);
});
});
Now, we can use our _checkAuth function internally using only promises, agnostic of the authHandler function implementation. As in:
handleHttp: function(req, res) {
var self = this;
// ...other processing
self._checkAuth(req).then(function (result) {
// check if the user is authed or not
if (result) {
// further process the request
} else {
// handle unauthorized request
}
}).catch(function (err) {
// handle internal server or api call (or whatever) error
});
}
The trick was to write our callback with a promise implementation. We always provide the authHandler a callback implementation, even if the authHandler does not use it. This way, we always make sure that the auth handler implementation returns a promise if it uses a callback style implementation.
All comments are welcomed and I would like to hear some opinions on this matter!
Thank you for your prompt responses!

Categories

Resources