I need help with promises and then callbacks.
I have tried reading guides but don't understand them.
var lastMessage = msg.channel.fetchMessages({ limit: 2 }).then(messages => {
return messages.last();
})
This returns Promise { < pending > }.
.then() statements don't make the program wait for them to be completed, they just execute their code after the Promise they're attached to is resolved.
You can either decide to move the rest of the code inside that .then() statement (but it'll get really messy) or use async/await.
If you are inside a function, you can declare that as an async function: that allows you to use the await keyword inside it. await makes the program wait for a Promise to resolve, and instead of a Promise it returns the value that you would use in the .then() function.
Here's an example:
client.on('message', async () => {
// You can do everything you would normally do here
// Using the 'async' keyword allows you to later user 'await'
var lastMessage = await msg.channel.fetchMessages({ limit: 2 }).then(messages => {
return messages.last();
});
});
Partially adapted from this answer (also mine)
Related
I'm struggling with callbacks in Node.js. I simply want playerNumber to be set to the number of players in my collection of Players. The console.log works, but I can't get the variable out of the function and into the playerNumber variable.
And if there's a simpler way get this value for use in the rest of my backend code, I'm all ears. I'm clearly new at Node.js, but the code always seems more involved than I'm expecting.
Thanks in advance!
var playerNumber = function countPlayers(callback){
Player.count(function(err, numOfDocs) {
console.log('I have '+numOfDocs+' documents in my collection');
callback(err, numOfDocs);
});
}
It's probably async, and it's a typical first-timer experience to want to "get back to normal" on the call chain on the way back from async call. This can't be done, but it's not so bad to live with it. Here's how...
Step 1: Promises are better than callbacks. I'll leave the long story
to others.
Step 2: Callbacks can be made into promises
In the OP case...
// The promise constructor takes a function that has two functions as params
// one to call on success, and one to call on error. Instead of a callback
// call the 'resolve' param with the data and the 'reject' param with any error
// mark the function 'async' so callers know it can be 'await'-ed
const playerNumber = async function countPlayers() {
return new Promise((resolve, reject) => {
Player.count(function(err, numOfDocs) {
err ? reject(err) : resolve(numOfDocs);
});
});
}
Step 3: Yes, the callers must deal with this, and the callers of the callers, and so on. It's not so bad.
In the OP case (in the most modern syntax)...
// this has to be async because it 'awaits' the first function
// think of await as stopping serial execution until the async function finishes
// (it's not that at all, but that's an okay starting simplification)
async function printPlayerCount() {
const count = await playerNumber();
console.log(count);
}
// as long as we're calling something async (something that must be awaited)
// we mark the function as async
async function printPlayerCountAndPrintSomethingElse() {
await printPlayerCount();
console.log('do something else');
}
Step 4: Enjoy it, and do some further study. It's actually great that we can do such a complex thing so simply. Here's good reading to start with: MDN on Promises.
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 know the setInterval func is to run some periodic task. But I want to know what the difference between async and sync func. Here is an example.
const fetchFile = async ()=>{//dosometing}
setInterval(async()=>{
fetchFile()
}, 1000)
setInterval(async()=>{
await fetchFile()
}, 1000)
setInterval(()=>{
fetchFile()
}, 1000)
There is no practical difference to the interval itself between any of your three implementations. setInterval() does not pay any attention to the return value from the callback so it doesn't matter at all that the async version returns a promise.
You can declare it async if you want to use await inside the callback for your own implementation, but that won't affect the event loop whether you use await or .then(). With await, as soon as you hit the await on a promise, the callback will return immediately and the event loop will be able to process other events. The same is true if you do fn().then(). While the asynchronous operation is running and the promise is waiting to get notified of completion, the event loop can process other events.
You may also want to know that there's no difference between these two:
fn(async()=>{
fetchFile()
}, 1000)
fn(async()=>{
await fetchFile()
}, 1000)
even outside of the setInterval() world. Doing an await on the last line of an async function doesn't add anything. It's just superfluous. But, in the setInterval() case, since setInterval() doesn't pay any attention to the return value from the callback, there's no practical difference between any of your three implementations.
In fact, there's no difference between return fetchFile() and return await fetchFile() either in an async function.
In all your examples, you have NO error handling on fetchFile(). If it rejects, you will have an unhandled rejection. To catch those errors, you would either surround an await with try/catch or use .catch().
First of all you pass async function callback to setInterval function which not expects async function in result you lack of proper error handling;
So if you want to run some periodic function I propose something like this, where you have more control on your code with error handling. Keep in mind that this could block event loop as your code could run thru microstask queeue only.
const util = require('util');
const sleep = util.promisify(setTimeout);
const fetchFile = async () => {
console.log('some async function');
};
async function fetchSomeFile() {
try {
await fetchFile();
sleep(1000);
fetchSomeFile();
} catch (err) {
console.log(err);
}
}
fetchSomeFile().catch(err => console.log(err));
I propose to watch good presentation - Broken Promises - James Snell, NearForm https://youtu.be/XV-u_Ow47s0
I have just started with async and await and trying to convert all my callback syntax to async/await style.
One thing I could not understand is, why I need to every time prefix my function with async keyword.
Here is the example:
APIQuery.js
makeRequest: async(options) => {
try {
var response = await(request(options1))
}
catch(err){
console.log("Some error occurred");
response = undefined;
}
return response;
}
MobileAPI.js
getMobileData: async modal => {
var options = {method: 'GET', json: true,uri: 'https://example.com/mobile/'+modal}
var response = await APIQuery.makeRequest(options);
}
MobileService.js
getMobileDataService: async modal => {
var response = await MobileAPI.getMobileData(modal);
}
MobileController.js
Similarly again I have to use async and await combination to return response.
So my question is, is there a way to get rid of using this everywhere. Calling async await inside APIQuery.js is not enough?
If you want to use the await operator, you have to use async keyword before function declaration:
The await operator is used to wait for a Promise. It can only be used inside an async function.
If you don't want to use async everywhere, you can continue using callbacks or Promises (then, catch, etc.).
So my question is, is there a way to get rid of using this everywhere.
You can't block. Period. As soon as you block, your server would become completely unresponsive to all requests until it's unblocked. For this reason, your code must be asynchronous.
Callbacks are a perfectly valid form of asynchrony, but async/await is easier to use, understand, and maintain.
I need help with debugging this code/or learn efficient way to do it- I tried using bluebird.each to capture all executions within my forEach, but didn't get it work. Same with setting up a new promise with pure javascript. I need help how to execute my forEach FIRST and move on.
let arr = [];
let fields = ['environment', 'habitat', 'earth]
Promise.each(fields, field => {
nano.db.use(field).view('options', 'options')
.spread((body, header) => {
arr.push(body.rows);
})
}).then(() => console.log(arr))
Expected outcome:
arr to console.log ====> [1,2,3,4,5]
Actual outcome:
arr is an empty array ====> [ ]
I see it's a problem with asynchronicity, but I can't seem to figure out how to actually make this work. any input or resources will be greatly appreciated!
I haven't actually ran your code so sorry if I'm incorrect, but from looking at it and the bluebird docs I assume the correction you need to make is return your nano.db call wrapped in a promise inside the Promise.each
let arr = [];
let fields = ['environment', 'habitat', 'earth']
Promise.each(fields, field => {
return new Promise ((resolve, reject) => {
nano.db.use(field).view('options', 'options')
.spread((body, header) => {
arr.push(body.rows);
resolve();
})
});
}).then(() => console.log(arr))
I believe your assumption is right that you're having a problem with asynchronicity when getting an empty array back instead of what you expect. I'm assuming the .then method is firing before the nano.db gets back with the data.
I wrapped your call of nano.db in a promise so that it will await nano.db finishing since Promise.each supports returning promises inside it.
Bluebird's promise docs state with Promise.each.
If the iterator function returns a promise or a thenable, then the
result of the promise is awaited before continuing with next
iteration.
So, if a promise is not returned in your Promise.each and anything that is asynchronous happens inside then just as with a then or a catch method on a promise under the same circumstances.
As I do not know bluebird there may be a way to change that promise to be more bluebird like. The promise I wrapped around the nano.db call is just a normal es6 promise which bluebird may or may not have a different api for creating promises.