I am new in the JS world, I am creating a query cache and I decide to use redis to cache the information, but I want to know if there is a way to use async/await keywords on the get function of redis.
const redis = require('redis');
const redisUrl = 'redis://127.0.0.1:6379';
const client = redis.createClient(redisUrl);
client.set('colors',JSON.stringify({red: 'rojo'}))
client.get('colors', (err, value) => {
this.values = JSON.parse(value)
})
I want to know if I can use the await keyword instead of a callback function in the get function.
You can use util node package to promisify the get function of the client redis.
const util = require('util');
client.get = util.promisify(client.get);
const redis = require('redis');
const redisUrl = 'redis://127.0.0.1:6379';
const client = redis.createClient(redisUrl);
client.set('colors',JSON.stringify({red: 'rojo'}))
const value = await client.get('colors')
With the util package i modified the get function to return a promise.
This is from redis package npm official documentation
Promises - You can also use node_redis with promises by promisifying node_redis with bluebird as in:
var redis = require('redis');
bluebird.promisifyAll(redis.RedisClient.prototype);
bluebird.promisifyAll(redis.Multi.prototype);
It'll add a Async to all node_redis functions (e.g. return client.getAsync().then())
// We expect a value 'foo': 'bar' to be present
// So instead of writing client.get('foo', cb); you have to write:
return client.getAsync('foo').then(function(res) {
console.log(res); // => 'bar'
});
// Using multi with promises looks like:
return client.multi().get('foo').execAsync().then(function(res) {
console.log(res); // => 'bar'
});
This example uses bluebird promisify read more here
So after you promsified a get to 'getAsync' you can use it in async await
so in your case
const value = await client.getAsync('colors');
For TypeScript users both util.promisify and bluebird.promisifyAll aren't ideal due to lack of type support.
The most elegant in TypeScript seems to be handy-redis, which comes with promise support and first-class TypeScript bindings. The types are generated directly from the official Redis documentation, i.e., should be very accurate.
Related
I have two methods.
The first one reads a file and writes to that file just as plain text. The second one writes a file as a stream.
In order to get this to work I have had to add fs twice in require.
const fs = require('fs').promises;
const fs2 = require('fs');
I'm trying to understand the difference and why I need this twice. But it sems that fs with out the promise doesn't have the ability to use createWriteStream and the one without the .promises doesnt have the ability to writeFile
/**
* Serializes credentials to a file compatible with GoogleAUth.fromJSON.
*
* #param {OAuth2Client} client
* #return {Promise<void>}
*/
async function saveCredentials(client) {
const content = await fs.readFile(CREDENTIALS_PATH);
const keys = JSON.parse(content);
const key = keys.installed || keys.web;
const payload = JSON.stringify({
type: 'authorized_user',
client_id: key.client_id,
client_secret: key.client_secret,
refresh_token: client.credentials.refresh_token,
});
await fs.writeFile(TOKEN_PATH, payload);
}
The second one writes to a file as a stream
/**
* Download file
* #param {OAuth2Client} authClient An authorized OAuth2 client.
*/
async function downloadFile(authClient) {
const service = google.drive({version: 'v3', auth: authClient});
const fileStream = fs2.createWriteStream("test.txt")
fileId = FILEID;
try {
const file = await service.files.get({
fileId: fileId,
alt: 'media',
}, {
responseType: "stream"
},
(err, { data }) =>
data
.on('end', () => console.log('onCompleted'))
.on('error', (err) => console.log('onError', err))
.pipe(fileStream)
);
} catch (err) {
// TODO(developer) - Handle error
throw err;
}
}
Note this does work, I am just trying to wrap my head around Node.js.
fs.promises contains a subset of the interface for what's on fs, but with promise-based interfaces instead of plain callback-style interfaces.
Some things which don't translate well to promises or don't have a natural promise-based interface such as fs.createReadStream() are only available on fs. Note that fs.createReadStream() returns a stream and uses events on the stream, not plain callbacks (which don't translate well to promises). As such, it's interface remains the same on fs and is not duplicated on fs.promises.
Many things are available in either with different interfaces:
fs.writeFile(filename, data, callback); // plain callback interface
or
await fs.promises.writeFile(filename, data) // promise interface
Most of the time, I can use only the fs.promises interface and do:
const fsp = require('fs').promises;
But sometimes, you need both and I would do this:
const fs = require('fs');
const fsp = fs.promises;
Keep in mind fs.promises is not a complete replacement for fs. It's an alternate (promise-based) interface for some (but not all) of the methods in the fs module.
Other interfaces such as fsp.open() have been enhanced and converted to promises in the fs.promises interface where it now returns a promise that resolves to an object-oriented fileHandle object whereas fs.open() just accepts a callback that will be passed a file descriptor.
So, my mode of operation is to look in the fs.promises interface for what I'm doing. If it's there, I use it there and use promises with it.
If it's not there, then go back to the fs interface for what I need.
I would advise you to NOT write code that uses the symbol fs for fs.promises. That will confuse people reading or working on your code because they are likely to think that a symbol named fs is the fs interface. That's why I use fs for the fs interface and fsp for the fs.promises interface in my code.
Is there any way to make AWS SSM getparameters sync?
Requirement :
The secret key, id stored in the SSM store should be accessible on the server up.
Using Node and express in the backend as a reverse proxy, so we have a constant.js file, it stores all the API URLs, paths, etc.
constats.js file
const api1url = 'http://example.com/path1'
const api1_secretkey = 'secret_key'
..................
module.export = {api1url,api1_secretkey}
So we wanted to call the ssm stuff in here before setting the const variables
const SSM = require('aws-sdk/clients/ssm');
const ssm = new SSM();
const params = {
Names: ['/secret_key_api_1', '/secret_key_api_2'],
WithDecryption: true,
};
const parameterList = await ssm.getParameters(params).promise();
I understand that await cant be without async, I just wanted to convey what I am expecting, without it being an async call or whether it be in the callback of getparameters.
const api1url = 'http://example.com/path1'
const api1_secretkey = parameterList.Parameter[1].Value
But since it is an async call we are not able to wait for it,tried doing it in a separate async function and then returning the data but since the function is still async having difficulties.
Not exactly issue wrt to an async function, the async function works as expected, but I want it to be synced, the AWS get parameter function is async. because of this I am not able to do something like const api1_secretkey = process.env.secret_key , this value will be obtained when js file is executed line by line. but since i am waiting for the secret key to come from async func by the time the line by line occurs const api1_secretkey = parameterList.Parameter[1].Value , the promise is still not resolved so undefined will sit. Even if i make a .then on the get params i can make this const api1_secretkey = parameterList.Parameter[1].Value after promise resolved. but since the export module is already done the other file carries undefined in the secret key even after it is changed on promise resolve.
I am trying to add bluebird promises in the project. I am using NodeJS, Express, Mongodb. This is my sample model file
const mongoose = require('mongoose')
// Blue Bird
mongoose.Promise = require('bluebird')
const schema = mongoose.SchemaAsync
const acModel = new schema({
// Schema here
}
})
module.exports = mongoose.modelAsync('myModel', acModel)
But is it necessary to put Async everywhere? For example SchemaAsync, modelAsync
I don't think you need to add Async at every call.
mongoose.Promise = require('bluebird');
User.findOne({}).then(function(user){
});
I guess you need to add async when you do this
Promise.promisifyAll(require("mongoose"));
Actually if you use async await you end up using the standard Promise object instead of bluebird
I'm trying to run 2 promises in paralel with sequelize, and then render the results in a .ejs template, but I'm receiving this error:
Promise.all(...).spread is not a function
This is my code:
var environment_hash = req.session.passport.user.environment_hash;
var Template = require('../models/index').Template;
var List = require('../models/index').List;
var values = {
where: { environment_hash: environment_hash,
is_deleted: 0
}
};
template = Template.findAll(values);
list = List.findAll(values);
Promise.all([template,list]).spread(function(templates,lists) {
res.render('campaign/create.ejs', {
templates: templates,
lists: lists
});
});
How can I solve thhis?
I'll make my comment into an answer since it solved your issue.
.spread() is not a standard promise method. It is available in the Bluebird promise library. Your code you included does not show that. Three possible solutions:
Access array values directly
You can just use .then(results => {...}) and access the results as results[0] and results[1].
Include the Bluebird Promise library
You can include the Bluebird promise library so you have access to .spread().
var Promise = require('bluebird');
Use destructuring in the callback arguments
In the latest versions of nodejs, you could also use destructuring assignment which kind of removes the need for .spread() like this:
Promise.all([template,list]).then(function([templates,lists]) {
res.render('campaign/create.ejs', {templates, lists});
});
You can write it without non-standard Bluebird features and keep less dependencies as well.
Promise.all([template,list])
.then(function([templates,lists]) {
};
ES6 Destructuring assignment
Promise.all([
Promise.resolve(1),
Promise.resolve(2),
]).then(([one, two]) => console.log(one, two));
This is a Bluebird Promise feature and you can access it via Sequelize.Promise without installing Bluebird module itself
Sequelize.Promise.all(promises).spread(...)
I needed to install BlueBird.
npm install bluebird
Then:
var Promise = require("bluebird");
I want to make a function that get the reslt of fingerprint2.js
Fingerprint2 is a Modern & flexible browser fingerprinting library http://valve.github.io/fingerprintjs2/
Usage:
new Fingerprint2().get(function(result, components){
console.log(result); //a hash, representing your device fingerprint
console.log(components); // an array of FP components
});
whatever try i did to get result of Fingerprint2 outside of new Fingerprint2().get(function(result, components){ was failed.
like Global vars and cookie because Fingerprint2().get(...) is asynchronous
Can it be written like a function to get fingerprint2 result?
for example:
var secure = getmefingerprint2();
Leverage with ES2017 feature async/await, you can use Fingerprint2.getPromise() like this:
(async () => {
const components = await Fingerprint2.getPromise();
const values = components.map(component => component.value);
const murmur = Fingerprint2.x64hash128(values.join(""), 31);
console.log('fingerprint:', murmur);
)()
See get and getPromise in Fingerprint2 Doc
This should be a comment but its a bit long.
Even if it were possible, you would be bypassing the published api, meaning you would have to maintain a fork of the original code. You would also need to invoke the functionality synchronously - and fingerprintjs2 runs asynchronously for good and obvious reasons.
You seem to be asking about an XY problem
How you should sole it depends on what you intend to do with the fingerprint after it has been captured.
You can't make async code act completely synchronous. However, you can use async/await, if your target browser has support, but it's not universally supported. Also, it only looks synchronous inside the async function
The basic idea is to return a promise, then await it inside an async function:
const getmefingerprint2 = async () => {
const secure = await (new Promise(resolve => {
new Fingerprint2().get((result, components) => resolve(result) )
}))
// do things with secure, whatever you return is thenable
return secure
}
that function could be called like this (because of Promises):
getmefingerprint2().then(result => {
// do stuff with result
})
but also, inside the async function, you could treat secure like you got it synchronously.
If you really wanted to make your async code act more sync (might be useful for other async code, too, if you hate async), you could wrap all your code in an async function, then use await to get async stuff:
const getFingerprint = () => new Promise(resolve => {
new Fingerprint2().get((result, components) => resolve(result) )
})
const main = async () => {
// do some of your app here
const secure = await getFingerprint()
// do more stuff here
}
main()
Or as an IIFE:
(async() => {
// do some of your app here
const secure = await getFingerprint()
// do more stuff here
})()
These are just kinda hacky workarounds that allow you to escape the burden of async code, which is maybe worth just getting to know, as it will make a better app. If you restructure your code to only have the things that depend on secure inside the callback, you'll get better performance, unblocked UI, and a more dynamic flow that is easy enough to reason about, once you get used to it.