Using async await with redis and bluebird in Nodejs - node.js

Correct me if I'm wrong here. This is what I do
client = Promise.promisifyAll(redis.createClient())
let reply = await client.getAsync('foo_rand000000000000')
console.log('reply',reply.toString())
And I got Unexpected token error.
I have this in my .babelrc
{
"presets": [
"es2015",
"stage-3"
]
}
Can someone point what I did wrong here.

As #Bergi points out, you need to wrap that in a async function
client = Promise.promisifyAll(redis.createClient())
async function main() {
let reply = await client.getAsync('whatever');
console.log('reply', reply.toString());
}
main();
To expand a bit, if you look at this docs http://babeljs.io/docs/plugins/transform-async-to-generator/ you'll notice that what they are doing is converting the function to a generator and yielding the resolved value of the promise to variable reply. Without wrapping this in a function that can be converted to a generator, you won't have the ability to pause execution and, therefore, would not be able to accomplish this.
Also, it should be noted, that this is not part of the standard. It is probably not going away, but the API could change. So I would not use this unless this is a toy project. You can accomplish something very similar using co or Bluebird.coroutine. They aren't quite as aesthetically pleasing, but the API won't change and the refactor once async/await get standardized will be trivial
Edit: add further explanation

Related

Calling a function that returns a AsyncIterableIterator without using "for await" block

I'm writing an AWS Lambda function in TypeScript using the Node.js runtime. I'm using a "batchDelete" function from a DynamoDB ORM library which returns an AsyncIterableIterator type.
According to the documentation here https://github.com/awslabs/dynamodb-data-mapper-js#batchDelete, I should invoke the method with a for await loop like this:
for await (const found of mapper.batchDelete(toRemove)) {
// items will be yielded as they are successfully removed
}
This all works great but the problem comes in where if I enable ESLint on my project. The default rules throw an error because the for await block is empty. I also get a warning because the found constant is never used. I have no use for the found constant and don't want to log it. I was wondering if there was another way to call an AsyncIterableIterator function where we disregard what is returned and don't have the empty block?
If you don't care about the results of the iteration, then you should probably just do something like this:
await Promise.all(toRemove.map(item => mapper.delete(item));
To use the mapper.batchDelete(toRemove) result more directly, you have to allow for multiple levels of promises. Perhaps you could do this:
await Promise.all(await mapper.batchDelete(toRemove)[Symbol.asyncIterator]());
In doing this, await mapper.batchDelete(toRemove)[Symbol.asyncIterator](), that would get you the default async Iterator and then passing it to Promise.all() would iterate it to get an iterable of promises. Unfortunately, in building it to make this easier:
for await (const found of mapper.batchDelete(toRemove))
they made it a bit more difficult to just get an array of promises out of it.
FYI, here's a link to the code for the .batchDelete() method if you want to look at how it's implemented.

Adding a value from Mongoose DB into a variable in Node.js

I am still quite new to Node.js and can't seem to find anything to help me around this.
I am having an issue of getting the query from my last record and adding it to my variable.
If I do it like below: -
let lastRecord = Application.find().sort({$natural:-1}).limit(1).then((result) => { result });
Then I get the value of the variable showing in console.log as : -
Promise { <pending> }
What would I need to do to output this correctly to my full data?
Here is it fixed:
Application.findOne().sort({$natural:-1}).exec().then((lastRecord) => {
console.log(lastRecord); // "lastRecord" is the result. You must use it here.
}, (err) => {
console.log(err); // This only runs if there was an error. "err" contains the data about the error.
});
Several things:
You are only getting one record, not many records, so you just use findOne instead of find. As a result you also don't need limit(1) anymore.
You need to call .exec() to actually run the query.
The result is returned to you inside the callback function, it must be used here.
exec() returns a Promise. A promise in JavaScript is basically just a container that holds a task that will be completed at some point in the future. It has the method then, which allows you to bind functions for it to call when it is complete.
Any time you go out to another server to get some data using JavaScript, the code does not stop and wait for the data. It actually continues executing onward without waiting. This is called "asynchronisity". Then it comes back to run the functions given by then when the data comes back.
Asynchronous is simply a word used to describe a function that will BEGIN executing when you call it, but the code will continue running onward without waiting for it to complete. This is why we need to provide some kind of function for it to come back and execute later when the data is back. This is called a "callback function".
This is a lot to explain from here, but please go do some research on JavaScript Promises and asynchronisity and this will make a lot more sense.
Edit:
If this is inside a function you can do this:
async function someFunc() {
let lastRecord = await Application.findOne().sort({$natural:-1}).exec();
}
Note the word async before the function. This must me there in order for await to work. However this method is a bit tricky to understand if you don't understand promises already. I'd recommend you start with my first suggestion and work your way up to the async/await syntax once you fully understand promises.
Instead of using .then(), you'll want to await the record. For example:
let lastRecord = await Application.find().sort({$natural:-1}).limit(1);
You can learn more about awaiting promises in the MDN entry for await, but the basics are that to use a response from a promise, you either use await or you put your logic into the .then statement.

Is there any way to get data from the database without using async/await in Nest.js?

Is there any way to use callback function for getting the data from the database using typeorm in nest.js and process that data, after that I want to send a response.
I am not sure that I understood your question correctly, but out of the box, you can use TypeORM (assuming you use a SQL DB, Mongoose works similarly, though). The repository functions return a Promise<>, so you could use something like this (from the docs):
return this.photoRepository
.find()
.then(result => {//... your callback code goes here...
});
You could wrap this code in a function getModifiedResult(cb){} and pass the callback into it. Secondly, Remember that async/await is just syntactic sugar for promises, so the above is equivalent to:
result = await this.photoRepository.find();
cbAction = //... do something with your result here
return cbAction;
Again, you could just wrap this.
Another idea is to wrap the promise in an Observable, using the RxJS from operator (fromPromise for RxJS versions < 6). You can then put your callback into the subscription:
//... Note that this returns a subscription for you to unsubscribe.
return from(this.photoRepository
.find()
.then(result => result))
.subscribe(result => //... your callback code
);
If you go down that route, however, it may be worthwhile to modify your results using RxJS operators, like map, switchMap,....
You can just use the from/of operators from rxjs.
Example
create(user: UserInterface): Observable<UserInterface> {
return from(this.userRepository.save(newUser))
}
And if you want you can also pipe the outcome
create(user: UserInterface): Observable<UserInterface> {
return from(this.userRepository.save(user)).pipe(
map((user: UserInterface) => user))
)
}
The answer is that you can use observables and / or promises (async await). I often use an observable for the wrapper function and then promises for addition work in a pipe. I'm not sure why I don't use observables for everything but it doesn't matter.
TypeORM integrates nicely with Nestjs and the docs show how to do the basics. With Postgres there is a problem with arrays that I'm trying to figure out though. An SO post and a Github issue have gone unanswered.
It looks like TypeORM, along with most modern JS packages, have been built with only promises in mind. Callbacks are, for the most part, not used in many programs today unless absolutely necessary, as promises and async/await syntax make the code much cleaner and more readable than the possible callback hell you may enter when using callbacks. It does look like sequelize accepts callbacks, and there are some docs in the recipes section about how to use NestJS with Sequelize
This is not much to do with Nest itself, it's just how you write your code and handle whatever libraries you might have. Let's say you have your database fetching function with a callback:
function findUsersWithCallback(function callback() {
// do something with db
callback(err, results);
});
You can wrap this into a promise-like function with, say, util.promisify
const findUsersPromisified = require('util').promisify(findUsersWithCallback);
What's left is to use your standard Nest provider:
#Injectable() UsersService {
findUsers() {
return findUsersPromisified();
}
}
Now your UsersService behaves like the rest of the framework, and your old callback-based code is nicely wrapped so you can safely ignore it.

How can I split my code, and keep it all asynchronous?

I've been coding just as a side project for a bit, piecing together bits that other people have written (it's for a simple discord bot). I want to split my code to make it easier to problem solve and read, however whenever I try to use the code it comes up with an error saying 'SyntaxError: await is only valid in async function'.
I've tried supposedly loading the code asynchronously, loading it with require() and then making a single command asynchronous, making the entire code in the file asynchronous (it's not just one command I want to load, but a whole file. Also I'm not sure if I tried it correctly or not), using the npm async-require, and maybe some others that have been around on the internet.
//one of the solutions I've tried. This is just copy pasted from the
//answer
//file2.js
var fs = require('fs');
module.exports = function (callback) {
fs.readFile('/etc/passwd', function (err, data) {
callback(err, data);
});
};
//file1.js
require('./passwords')(function (err, passwords) {
// This code runs once the passwords have been loaded.
});
In the first file before I split it, I started it with client.on('message', async message => { and it made me able to use the await function in every command. I want to still be able to do that, but just have it a bit neater and easier to use by splitting it.
I'm trying to get this done so I can move on to a different question I asked and give one of the answers a tick. Any help would be greatly appreciated <3
Fix those awaits so that they are not inside async functions. This is a lexical issue that can be solved just by looking at the location were the error occurs. Just look for the nearest containing function to where the await is and mark it async. Repeat until the error goes away.

node.js module self talk back to js that requires it

im having problems understanding how to talk 'up and down' between app.js and modules...
I think its with a callback but i've also seen things like self._send(), this.send() and module.exports.emit
I'm quite confused.
I recently installed pdfkit from npm (quite good 6/10 :p) I want to learn by improving it slightly though by adding a done event/callback for doc.write().
I know its not that important but i've been looking through my installed modules and that is probably the easiest example of code that wouldn't hurt to have a 'DONE' I also figured this function would be good to learn from as it uses fs.writeFile which has a function(){} that fires when its finished writing so the fact that i can see where in the code it ends makes it an easy learning tool.
I've modified the code a few times tried to compare modules to see where similar things have been done but i just keep breaking it with errors, i don't feel like i'm getting anywhere:
inside the pdfkit module document.js i've made changes:
var EventEmitter = require('events').EventEmitter;//ben
module.exports = new EventEmitter();//ben
PDFDocument.prototype.write = function(filename, fn, callback) {//ben added callback
return this.output(function(out) {
return fs.writeFile(filename, out, 'binary', fn, function(){//ben added finished function
//module.exports.emit('pdf:saved');//ben
callback();//ben
});
});
};
in my app.js:
doc.write('public_html/img/'+_.c+'_'+_.propertyid+'.pdf',function(){console.log('pdf:saved');});
//doc.on('pdf:saved',function(){console.log('pdf:saved');});
I'm also not really sure what i'm querying on google, please can someone help me?
EventEmitter is required to create objects with event storage, and emit/catch events.
While what you are using in your example is called 'callback'.
It is two different ways, and can be sort of cross used. Sometimes it is good to use events, but sometimes just callback is enough.
The best way to have head around it: play with callbacks (forget about events for now). Try to think of different uses of callbacks and maybe even have callback function and pass it around. Then come to callback chains. And only after start playing with EventEmitter. Remember that EventEmitter is different thing from callbacks, with sometimes compatible use cases, but generally is used in different cases.
Here is your code, simplified with same functionality as you have/need atm:
PDFDocument.prototype.write = function(filename, callback) {
this.output(function(out) {
fs.writeFile(filename, out, 'binary', callback);
});
};
And use it the way you already do.
Do not try to generate garbage of code that will only complicate everything - it is better to study speficic areas seperatelly, and then switch to next one. Otherwise will mess up in mind.
FIXED
fn is the callback function!
PDFDocument.prototype.write = function(filename, fn) {
return this.output(function(out) {
return fs.writeFile(filename, out, 'binary', fn);
});
};
and by naming my callback function to fn it works!
doc.write('public_html/img/'+_.c+'_'+_.propertyid+'.pdf',function fn(){console.log('pdf:saved');});
for me that is a massive learning mountain climbed!!

Resources