Is it possible to use await inside a normal function?
For Example:
function myFunction(v1, v2) {
let v3 = await some db operation; returns a array
console.log(v3);
//do something
};
Yes, all async code is called from a normal function somewhere, but no you can't use the await keyword in a non-async function.
Async functions look like promises when inside non-async functions.
function myOuterFunction(v1, v2) {
myFunction(v1, v2)
.then(console.log)
.catch(console.error);
}
async function myFunction(v1, v2) {
let v3 = await some db operation; returns an array
console.log(v3);
//do something
};
(This example uses the functions console.log and console.error to handle returned values and exceptions.)
No, and for a good reason.
Before async functions were introduced: the following was entirely possible:
function foo() {
var await = 42;
var result = await + 42;
}
If they had made it so await was available in normal functions, that code would have been retroactively broken, causing what's called a backwards compatibility break.
This is also why yield is only available within function*.
No. The "magic" of asynchronous programming – that, in JavaScript, includes the usage of await – is that it doesn't block the execution of other code. If you want to use it, you have to adapt your codebase to use async functions where it makes sense.
If you really need to wait for asynchronous actions to complete inside normal synchronous functions, you could check whether the library you're using also offers sync functions (fs-extra for example does). But please, unless there's a really good reason not to, make your code asynchronous.
Related
When I hover on the keyword 'function' the description says:
"(local function)(this: any, next: (err?: mongoose.CallbackError | undefined) => void): Promise<void>"
So does It return a Promise<void> or a simple <void>? I can't even understand what does this function returns? And to be honest I don't understand really well the concept of Promise<void>...
userSchema.pre('save', async function (next) {
let user = this as UserDocument;
if(!user.isModified('password')){
return next();
}
const salt = await bcrypt.genSalt(config.get<number>('saltWorkFactor'));
const hash = await bcrypt.hash(user.password, salt);
user.password = hash;
return next();
})
This question is really interesting. Your function returns a Promise<void>, which is compatible with the void return type that pre is expecting, but Mongoose is quietly smart enough to know what to do with your Promise so you don't even have to call next at all.
First some background:
void has a special meaning in TypeScript to mean that the return value could be any value; the value is frequently undefined (because that's what a function returns without a return statement) but it doesn't have to be. As in the TypeScript FAQ, this makes it convenient to accept or pass functions that return a value by indicating the return value is unused. If you need to supply a function with return type void, you could pass back a function that returns a string, Promise<void>, Promise<SomeObject>, null, undefined, or anything else.
All async functions return Promises, and this is no exception. A Promise<number> is a Promise that says that its then function will receive a number; a Promise<void> is a Promise that doesn't tell you anything about what its then function receives. The then function will still be called, unless it has an error to catch; you just don't know much about its argument.
In Mongoose's types, pre takes a PreSaveMiddlewareFunction<T> function, which is the type of the function you wrote. It accepts a function called next and returns void: Mongoose claims not to care what you return. Your middleware function is allowed to be asynchronous; when you're done you're expected to call next (with an error object, if you have one), and that call to next also returns void.
Your function passed to pre returns type Promise<void>: The function is async so it absolutely returns a promise, and your return next(); means that the Promise resolves to whatever next returns, which is defined as void. You don't know what next returns and shouldn't care about it. You don't even need to return next(), you just need to call it: It's just a callback so you can tell Mongoose your middleware is done and report any errors.
So your async function returns Promise<void>, but that works with the definition of pre: pre doesn't care what kind of return value your function has (void) as long as you call next to indicate you're done.
But wait! Reporting that your asynchronous function is done and whether or not there were errors is exactly the problem that Promises were designed to solve, and the next callback pattern is exactly the kind of pattern that Promises were designed to replace. If you're returning a Promise, why would you need to call next at all when Mongoose can just watch the promise you return?
In fact, in Mongoose 5.x or later, that's exactly what happens: If the function you pass into pre returns a Promise, then you can use that instead of calling next. You can still call next manually for compatibility's sake, but in your case you could delete return next() and everything would keep working. See the middleware docs:
In mongoose 5.x, instead of calling next() manually, you can use a function that returns a promise. In particular, you can use async/await.
schema.pre('save', function() {
return doStuff().
then(() => doMoreStuff());
});
// Or, in Node.js >= 7.6.0:
schema.pre('save', async function() {
await doStuff();
await doMoreStuff();
});
The docs further explain why return next() is a pattern at all:
If you use next(), the next() call does not stop the rest of the code in your middleware function from executing. Use the early return pattern to prevent the rest of your middleware function from running when you call next().
const schema = new Schema(..);
schema.pre('save', function(next) {
if (foo()) {
console.log('calling next!');
// `return next();` will make sure the rest of this function doesn't run
/*return*/ next();
}
// Unless you comment out the `return` above, 'after next' will print
console.log('after next');
});
In summary, the expected return type of void is compatible with the fact that you're returning a Promise<void>, but it hides the fact that recent versions of Mongoose are smart enough to check whether you're returning a Promise and do the right thing without needing a call to next. They're two different styles that both work.
Long answer short: It return a Promise<void>
Callbacks
To understand why, here are some details.
First one must understand Callbacks in node.js. Callbacks are one of the basic structure/feature of how node.js works.
You could say that node.js is basically an Event-Driven Programming "framework" (most people will frown to the framework word...). That means that you tell node that in the event of a certain thing happening, it should do a certain action/function (callback).
For node to understand us, we normally give the callback function as a parameter to another function that will do the work of "listening to the event" and executing the callback that we give it. So it is not "us" that execute the callback, it is the event listener.
In your case,
userSchema.pre('save', async function (next) {
pre is the function (a method in Mongoose's userSchema), save is the event that one must react to, async function (next) { is the callback or what must be done after the event.
You will note that your callback is returning next(), but next() returns void, which mean that your callback is returning void.
So why is it returning Promise<void>?
The fact is that in your case, your callback is an async function. And every async functions will return a promise. It is an async function because it is awaiting another promise (two promises even) inside of it. They are hidden because of the await
const salt = await bcrypt.genSalt(config.get<number>('saltWorkFactor'));
const hash = await bcrypt.hash(user.password, salt);
Note: The bcrypt methods are very expensive in terms of CPU and time (also a security feature among other things).
It also means that normally in your code
const hash = await bcrypt.hash(user.password, salt);
user.password = hash;
you couldn't have available "right away" the hash value for the user.password and, worse, you couldn't even know when it would come. Will your program stop and wait until bcrypt finish its business?
If you have many async functions, your program will be a great favourite for the slowest champion in the Olympics.
What is going on with those promises and how can we not be labelled as a geriatric program?
Promises
Here is a quick/long comment to try to explain the concept of promises.
In "normal" code, each lines of code is executed and "finished" before the next one. Ex: (with cooking)
Combine the Butter and Sugar,
Add Eggs One at a Time, etc.
Or in your code:
let user = this as UserDocument;
if(!user.isModified('password')){
return next();
}
A promise is a certain code that is executed but not finished before the next line of code. Ex:
while the cake is in the oven (promise),
you prepare the frosting,
but you can't put it until the cake in baked (the "then" action of promises).
Note: Your code is using await so there is no "explicit" then method.
You will have many example of "promises" things in everyday life. you may have heard of asynchronous code = not one after the other, not in sync, ...
Turning on an alarm to wake you in the morning, then you make the promise that you will not ignore it;
putting a reminder on the calendar then you make the promise that you will go to that job interview; etc.
All the while, you continue with your life after making those promises.
In code, a function that returns a promise will have a then method where you tell the computer what to do when when the "alarms goes off".
It is usually written like this
mypromise().then(doThisThingFunction)
const continueWithMyLife = true
In this way the then method is very similar to the callback of node.js. It is just expressed in a different way in the code and is not specific to node (callbacks are also not specific to node...).
One very important difference between them is that callbacks are something that the listener "do" and promises is something that resolves (hopefully) to a returning value.
Async/Await
Nowadays it is common to use async/await. Fortunately/unfortunately it basically hides the asynchronous behaviour. Better flow of reading the code, but also much worse understanding of promises for new programmers.
After a await, there is no then method (Or you could say that the following line of code is the then action). There is no "continuing with your life". There is only "waiting until the alarms goes off", So the next line after the await is essentially the "get out of the bed action".
That is why, in your code, the hash value is available in the next line. Basically in the "old way" to write promises
user.password = hash;
would be inside the then function.
And that is also why it is returning Promise<void>
But still, all these analogies won't really help. The best is to try it in everyday code. There is nothing like experience to understand anything.
I am really struggling here. Admittedly I am no guru especially when it comes to node and asynchronous programming, I am an old C# .net developer so I am comfortable with code but struggling here.
Here's the back story, short and sweet. I have a pg database and I am using the sequelize ORM tools to create a relatively simple CRUD app.
Here's what I want to do.
Make a call to the findAll function on one object.
I need a piece of information from that first call so that I can make a subsequent call.
For instance. Lookup the current user to get their details, grab their ID and now lookup their display preferences.
I know I can run two requests that are not linked using Promise.all, here is an example of this already working.
var delConfig = deliverabiltyConfigs.findAll2(req.signedCookies.tsUser);
var delPack = deliverabilityPackages.findAll2();
Promise.all([delConfig, delPack]).then((results) =>{
res.render('index', { title: 'Deliverability Calculator', UserEmail : req.signedCookies.tsUser, UserName : req.signedCookies.tsUserName, data:results[0], packs:results[1]});
});
Where I am stuck is passing data from one promise to then next and needing them to run asynchronously.
Please help!
There are a few way you can do this. Either use promise chaining or with async & await.
Promise chaining might be the simplest way to do this now, but I would suggest using async await as its easier to read. Since you didn't really provide a sample of what you were trying to do I will make something generic that should hopefully help.
So using promise chaining you would do something like:
pgConnection.findAll().then((data) => {
const foo = data.foo;
pgConnection.findSomething(foo).then((data2) => {
console.log(data2);
});
});
What is happening here is once the promise from findAll() is resolved successfully it will call the .then method and will pass the resulting data there for you to use in your next db query and then I am just printing out the result of the final db query.
This is how you could do it using async & await:
async function getFoo() {
const data = await pgConnection.findAll();
const foo = data.foo;
const data2 = await pgConnection.findSomething(foo);
console.log(data2);
}
The await keyword can only be used inside of an async function so it might not be as simple to change as just using a .then promise chain.
I am looking for a answer on what to use in my nodeJS app.
I have code which handles my generic dB access to mssql. This code is written using an async functions and then I used a promise to call that function and all works fine.
As my app is getting bigger and code larger I am planning to move some of the logic into functions and then call them.
So my question is: is there a drawback to using a mix of async/await and promises or does it really not matter?
Async / await makes it easier to write more readable code as I have to read and write to multiple db’s before I return something and I need results of some of these.
So the question is what is the better approach?
Async / await on dB layer that’s set and can’t change
The logic layer async / await which would allow me a async / and await on the function call or if I go with promise for logic then I am stuck with promise on function call.
So I hope someone can give me more insight if one has more advantages than the other, besides being able to write cleaner code.
async/await and promises are closely related. async functions return promises, and await is syntactic sugar for waiting for a promise to be resolved.
The only drawback from having a mix of promises and async functions might be readability and maintainability of the code, but you can certainly use the return value of async functions as promises as well as await for regular functions that return a promise.
Whether you choose one vs the other mostly depends on availability (does your node.js / browser support async?) and on your aesthetic preference, but a good rule of thumb (based on my own preference at the time of writing) could be:
If you need to run asynchronous code in series: consider using async/await:
return asyncFunction()
.then(result => f1(result))
.then(result2 => f2(result2));
vs
const result = await asyncFunction();
const result2 = await f1(result);
return await f2(result2);
If you need nested promises: use async/await:
return asyncFunction()
.then(result => {
return f1(result)
.then(result2 => f2(result, result2);
})
vs
const result = await asyncFunction();
const result2 = await f1(result);
return await f2(result, result2);
If you need to run it in parallel: use promises.
return Promise.all(arrayOfIDs.map(id => asyncFn(id)))
It has been suggested you can use await within an expression to await multiple tasks like so:
*note, this still awaits in sequence from left to right, which is OK if you don't expect errors. Otherwise the behaviour is different due to fail fast behaviour of Promise.all()
const [r1, r2, r3] = [await task1, await task2, await task3];
(async function() {
function t1(t) {
console.time(`task ${t}`);
console.log(`start task ${t}`);
return new Promise((resolve, reject) => {
setTimeout(() => {
console.timeEnd(`task ${t}`);
resolve();
}, t);
})
}
console.log('Create Promises');
const task1 = t1(100);
const task2 = t1(200);
const task3 = t1(10);
console.log('Await for each task');
const [r1, r2, r3] = [await task1, await task2, await task3];
console.log('Done');
}())
But as with Promise.all, the parallel promises need to be properly handled in case of an error. You can read more about that here.
Be careful not to confuse the previous code with the following:
let [r1, r2] = [await t1(100), await t2(200)];
function t1(t) {
console.time(`task ${t}`);
console.log(`start task ${t}`);
return new Promise((resolve, reject) => {
setTimeout(() => {
console.timeEnd(`task ${t}`);
resolve();
}, t);
})
}
console.log('Promise');
Promise.all([t1(100), t1(200), t1(10)]).then(async() => {
console.log('Await');
let [r1, r2, r3] = [await t1(100), await t1(200), await t1(10)]
});
Using these two methods is not equivalent. Read more about the difference.
In the end, Promise.all is a cleaner approach that scales better to an arbitrary number of tasks.
Actually it depends on your node version, But if you can use async/await then your code will be more readable and easier to maintain.
When you define a function as 'async' then it returns a native Promise, and when you call it using await it executes Promise.then.
Note:
Put your await calls inside a try/catch, because if the Promise fails it issues 'catch' which you can handle inside the catch block.
try{
let res1 = await your-async-function(parameters);
let res2 = await your-promise-function(parameters);
await your-async-or-promise-function(parameters);
}
catch(ex){
// your error handler goes here
// error is caused by any of your called functions which fails its promise
// this methods breaks your call chain
}
also you can handle your 'catch' like this:
let result = await your-asyncFunction(parameters).catch((error)=>{//your error handler goes here});
this method mentioned does not produce an exception so the execution goes on.
I do not think there is any performance difference between async/await other than the native Promise module implementation.
I would suggest to use bluebird module instead of native promise built into node.
At this point the only reason to use Promises is to call multiple asynchronous jobs using Promise.all() Otherwise you’re usually better with async/await or Observables.
Its depending upon what approach you are good with, both promise and async/await are good, but if you want to write asynchronous code, using synchronous code structure you should use async/await approach.Like following example, a function return user with both Promise or async/await style.
if we use Promise:
function getFirstUser() {
return getUsers().then(function(users) {
return users[0].name;
}).catch(function(err) {
return {
name: 'default user'
};
});
}
if we use aysnc/await
async function getFirstUser() {
try {
let users = await getUsers();
return users[0].name;
} catch (err) {
return {
name: 'default user'
};
}
}
Here in promise approach we need a thenable structure to follow and in async/await approach we use 'await' to hold execution of asynchronous function.
you can checkout this link for more clarity Visit https://medium.com/#bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8
Yesterday I made a tentative decision to switch from using Promises to using Async/Await, independent of nodejs, based on the difficulty in accessing previous values in the Promise chain. I did come up with a compact solution using 'bind' to save values inside the 'then' functions, but Async seemed much nicer (and it was) in allowing direct access to local variables and arguments. And the more obvious advantage of Async/Await is, of course, the elimination of the distracting explicit 'then' functions in favor of a linear notation that looks much like ordinary function calls.
However, my reading today uncovered problems with Async/Await, which derail my decision. I think I'll stick with Promises (possibly using a macro preprocessor to make the 'then' functions look simpler) until Async/Await gets fixed, a few years from now.
Here are the problems I found. I'd love to find out that I am wrong, that these have easy solutions.
Requires an outer try/catch or a final Promise.catch(), otherwise errors and exceptions are lost.
A final await requires either a Promise.then() or an extra outer async function.
Iteration can only be properly done with for/of, not with other iterators.
Await can only wait for only one Promise at a time, not parallel Promises like Promise chains with Promise.all.
Await doesn't support Promise.race(), should it be needed.
I understand what a callback is and what asynchronous means, what I don't get is how to run asynchronous functions in node.
For example, how is this
var action = (function(data,callback) {
result = data+1;
callback(result);
});
http.createServer(function (req, res) {
action(5, function(r){
res.end(r.toString());
});
}).listen(80);
different from this
var action = (function(data) {
result = data+1;
return result;
});
http.createServer(function (req, res) {
var r = action(5);
res.end(r.toString());
}).listen(80);
?
I guess in the first example I'm doing it asynchronously, yet I don't know how Node knows when to do it sync or async... is it a matter of the return? or the fact that in the sync mode we're doing var x = func(data);?
And also: when to use sync or async? Because obviously you don't want to use it when adding +1... is it OK to use async just when performing IO tasks, such as reading from DB?
For example, I'm using the library crypto to encrypt a short string (50 chars at most), is this case a good example where I should already be using async?
I guess in the first example I'm doing it asynchronously...
Your first example isn't async :) Merely passing a callback and calling it when you're done doesn't make a function asynchronous.
Asynchronous means that, basically, you're telling Node: "here, do this for me, and let me know when you're done while I continue doing other stuff".
Your example is not handing anything to Node for future completion. It's doing a calculation and calling the callback immediately after that. That's functionally the same as your second example, where you return the result of the calculation.
However, you can change your first example to something that is asynchronous:
var action = (function(data,callback) {
setTimeout(function() {
result = data + 1;
callback(result);
}, 1000);
});
Here, you're telling Node to delay calling the callback for one second, by using setTimeout. In the mean time, Node won't get stuck waiting for a second; it will happily accept more HTTP requests, and each one will be delayed one second before the response is sent.
When to use sync or async?
Asynchronous code is "viral": if you rely on functions that are async, your own code that uses those functions will also have to be async (generally by accepting a callback, or using another mechanism to deal with asynchronicity, like promises).
For example, I'm using the library crypto to encrypt a short string (50 chars at most), is this case a good example where I should already be using async?
This depends on which function you're using. AFAIK, most encryption functions in crypto aren't asynchronous, so you can't "make" them asynchronous yourself.
Both examples will work synchronous. Simple async operations are setTimout and setInterval.
Node actually doesn't care what code are you running. You can block or not (blocking/non-blocking).
In other words - you have event loop. If your process is async he will pass the program control to the event loop, so it can execute any other action node needs to be done. If not - he wont.
if you want a function to work asynchronously, you can do that using promises, look at the code below :
function is_asynch(){
return new Promise((resolve,reject)=>{
resolve( here_your_synch_function() )
})
}
I'm new to node.js and using it for a backend that takes data from syslog messages and stores it to a database.
I've run into the following type of serial operations:
1. Query the database
2. If the query value is X do A. otherwise do B.
A. 1. Store "this" in DB
2. Query the database again
3. If the query value is Y do P. otherwise do Q.
P. Store "something"
Q. Store "something else"
B. 1. Store "that" in the DB
2. Store "the other thing" in the DB
The gist here is that I have some operations that need to happen in order, but there is branching logic in the order.
I end up in callback hell (I didn't know what that is when I came to Node.. I do now).
I have used the async library for things that are more straight forward - like doing things in order with async.forEachOfSeries or async.queue. But I don't think there's a way to use that if things have to happen in order but there is branching.
Is there a way to handle this that doesn't lead to callback hell?
Any sort of complicated logic like this is really, really going to benefit from using promises for every async operation, especially when you get to handling errors, but also just for structuring the logic flow.
Since you haven't provided any actual code, I will make up an example. Suppose you have two core async operations that both return a promise: query(...) and store(...).
Then, you could implement your above logic like this:
query(...).then(function(value) {
if (value === X) {
return store(value).then(function() {
return query(...).then(function(newValue) {
if (newValue === Y) {
return store("something");
} else {
return store("something else");
}
})
});
} else {
return store("that").then(function() {
return store("the other thing");
});
}
}).then(function() {
// everything succeeded here
}, function(err) {
// error occurred in anyone of the async operations
});
I won't pretend this is simple. Implemented logic flow among seven different async operation is just going to be a bit of code no matter how you do it. But, promises can make it less painful than otherwise and massively easier to make robust error handling work and to interface this with other async operations.
The main keys of promises used here are:
Make all your async operations returning promises that resolve with the value or reject with the failure as the reason.
Then, you can attach a .then() handler to any promise to see when the async operation is finished successfully or with error.
The first callback to .then() is the success handler, the second callback is the error handler.
If you return a promise from within a .then() handler, then that promise gets "chained" to the previous one so all success and error state becomes linked and gets returned back to the original promise state. That's why you see the above code always returning the nested promises. This automates the returning of errors all the way back to the caller and allows you to return a value all the way back to the caller, even from deeply nested promises.
If any promise in the above code rejects, then it will stop that chain of promises up until an actual reject handler is found and propagate that error back to that reject handler. Since the only reject handler in the above code is at the to level, then all errors can be caught and seen there, no matter how deep into the nested async mess it occurred (try doing that reliably with plain callbacks - it's quite difficult).
Native Promises
Node.js has promises built in now so you can use native promises for this. But, the promise specification that node.js implements is not particularly feature rich so many folks use a promise library (I use Bluebird for all my node.js development) to get additional features. One of the more prominent features is the ability to "promisify" an existing non-promise API. This allows you to take a function that works only with a callback and create a new function that works via a promise. I find this particularly useful since many APIs that have been around awhile do not natively return promises.
Promisifying a Non-Promise Interface
Suppose you had an async operation that used a traditional callback and you wanted to "promisify it". Here's an example of how you could do that manually. Suppose you had db.query(whatToSearchFor, callback). You can manually promisify it like this:
function queryAsync(whatToSearchFor) {
return new Promise(function(resolve, reject) {
db.query(whatToSearchFor, function(err, data) {
if (!err) {
reject(err);
} else {
resolve(data);
}
});
});
}
Then, you can just call queryAsync(whatToSearchFor) and use the returned promise.
queryAsync("foo").then(function(data) {
// data here
}, function(err) {
// error here
});
Or, if you use something like the Bluebird promise library, it has a single function for promisifying any async function that communicates its result via a node.js-style callback passed as the last argument:
var queryAsync = Promise.promisify(db.query, db);