function testFunc(name) {
return new Promise(resolve => {
setTimeout(() => resolve('Hello there ' + name + '!'), 3000)
})
}
console.log("Calling testFunc !!!!")
testFunc('Sam').then(data => console.log(data))
console.log("Done !!!!")
The code above logs Calling testFunc !!!! then Done !!!! then Hello there Sam!
How can I use async/await in this situation to log Calling testFunc !!!! then Hello there Sam! then Done !!!!
Thanks in advance
Because 'textFunc' is asynchronous, meaning it takes a couple seconds to complete, console.log('done') will get executed before .then(...). So you can just add console.log('done') into the .then(...) part, or use something like the code below.
console.log("Calling testFunc !!!!")
let data = await testFunc('Sam')
console.log(data)
console.log("Done !!!!")
you might also have to wrap everything in an async function
async someFunction() {
console.log("Calling testFunc !!!!")
let data = await testFunc('Sam')
console.log(data)
console.log("Done !!!!")
}
someFunction()
Related
I am working on a GraphQL query where I am trying to find a unique model. However, nothing ever gets returned because the code kept carrying on before the query was finished, thus attempted to return a Promise when it expected a Model. The code looks as follows...
const findShift = async (date) => {
console.log("In mutation function")
const foundShift = await db.shift.findUnique({
where: {
date: date
}
})
return foundShift
}
const foundShift = findShift(date).then( resolved => {
console.log("printing resolved...")
console.log(resolved)
if (resolved.id != 'undefined'){
console.log({
id: resolved.id,
date: resolved.date,
allDevices: resolved.allDevices
})
return foundShift
}
else{
throw new Error("no shift of that date found!")
}
})
And the console.log statements make the console look as so...
In mutation function
Promise { <pending> }
prisma:info Starting a postgresql pool with 9 connections.
and ultimately the query just returns null. As you see, I tried using then and putting the mutation itself into an entirely different function just to circumvent these asynchronisity issues to no avail. Does anyone see a workaround?
First off, ALL async functions return a promise. The return value in the async function becomes the resolved value of that promise. So, the caller of an async function MUST use .then() or await to get the resolved value from the async function. There is no way to "circumvent" the asynchronicity like you are attempting. You can tame it to make it more usable, but you can't escape it. So, your async function returns a pending promise that will eventually resolve to whatever value you return inside your async function.
You can read more about how async functions work here in this other answer.
In trying to make a minimal, reproducible example of your code, I've reduced it to this where I've substituted an asynchronous simulation for the database call:
function delay(t, v) {
return new Promise(resolve => setTimeout(resolve, t, v));
}
// simulate asynchronous database operation
const db = {
shift: {
findUnique: function(data) {
return delay(100, { id: 123, date: Date.now(), allDevices: ["iPhone", "Galaxy", "Razr"] });
}
}
}
const findShift = async (date) => {
console.log("In mutation function")
const found = await db.shift.findUnique({
where: {
date: date
}
})
return found;
}
const date = Date.now();
const foundShift = findShift(date).then(resolved => {
console.log("printing resolved...")
console.log(resolved);
if (resolved.id != 'undefined') {
console.log({
id: resolved.id,
date: resolved.date,
allDevices: resolved.allDevices
})
return foundShift
} else {
throw new Error("no shift of that date found!")
}
});
When I run this in nodejs, I get this error:
[TypeError: Chaining cycle detected for promise #<Promise>]
And, the error is caused by this line of code:
return foundShift
You are attempting to return a promise that's already part of this promise chain from within the promise chain. That creates a circular dependency which is not allowed.
What you need to return there is whatever you want the resolved value of the parent promise to be. Since that looks like it's the object you construct right above it, I've modified the code to do that. This code can be run and foundShift is a promise that resolves to your object.
function delay(t, v) {
return new Promise(resolve => setTimeout(resolve, t, v));
}
// simulate asynchronous database operation
const db = {
shift: {
findUnique: function(data) {
return delay(100, { id: 123, date: Date.now(), allDevices: ["iPhone", "Galaxy", "Razr"] });
}
}
}
const findShift = async (date) => {
const found = await db.shift.findUnique({
where: {
date: date
}
})
return found;
}
const date = Date.now();
const foundShift = findShift(date).then(resolved => {
if (resolved.id != 'undefined') {
let result = {
id: resolved.id,
date: resolved.date,
allDevices: resolved.allDevices
};
return result;
} else {
throw new Error("no shift of that date found!")
}
});
// foundShift here is a promise
// to get it's value, you have to use .then() or await on it
foundShift.then(result => {
console.log("final result", result);
}).catch(e => {
console.log(e);
});
Here are a couple of rule about promises that might help:
All fn().then() or fn().catch() calls return a new promise that is chained to the one that fn() returned.
All async functions return a promise.
You cannot "circumvent" asynchronicity and somehow directly return an asynchronously retrieved value. You will have to use a callback, an event or return a promise (or some similar asynchronous mechanism) in order to communicate back to the caller an asynchronously retrieved value.
await can only be used inside an async function (or at the top level of an ESM module).
The first await in a function suspends execution of the async function and then immediately returns an unfulfilled promise to the caller. So, the await only affects the current function flow, not the caller's flow. The caller will still have to use .then() or await to get the value out of the promise that the async function returns.
Try as you might, there is no way around these rules (in Javascript as it currently runs in a browser or in nodejs).
I'm trying to get make the async calls bellow (they are async because of a external API, not my design) to run sequentially, now I managed to have foo be awaited by it's calling function but I'm having trouble awaiting for foo2 because I get the following error on the async line
JS ERROR: SyntaxError: missing ) after argument list
What am I missing?
ps: Also is there a better way to "return" a value from the callback than setting a global variable and accessing it from outside?
foo(nick) {
return new Promise((resolve, reject) async () => {
async_foo(par, [],
(c, res) => {
let par2;
try {
par2 = c.somefun(res);
} catch (e) {
logError(e, `Some error`);
return;
}
let output = await this.foo2(par2);
resolve(output);
});
});
}
foo2(par2) {
return new Promise((resolve, reject) => {
par2.asyncfun(
null, this.callback.bind(this, par2));
});
}
Thank you in advance
I think you're just trying to do too much in one Promise:
async function(nick) {
let res1 = await new Promise((resolve, reject) => {
async_foo(par, [], (c, res) => {
try {
resolve(async_foo_finish(res));
} catch (e) {
reject(e);
}
});
});
return new Promise((resolve, reject) => {
res1.asyncfunc(null, (obj, res) => {
try {
resolve(obj.asyncfun_finish(res));
} catch (e) {
reject(e);
}
});
});
}
foo('something').then(output => {
log('output');
}).catch(e => {
logError(e);
});
It's hard to give good advice, since you're not showing real functions.
One of the main purposes of Promises/async-await is to avoid complicated callback nesting. You should generally break your chain of functions into separate Promises, then await them one after the other.
in the code below, I want to get msg#1, msg#2, msg#3 in this order. I'm getting right now: msg#1, msg#3, msg#2. thanks for help ! Denys
function timeoutPromise(time) { return new Promise(function (resolve) { setTimeout(function () { resolve(Date.now()); }, time) }) }
function wait(howlong) { return timeoutPromise(howlong * 1000); }
async function doAsync() {
var start = Date.now(), time;
time = await wait(1); console.log('... ' + (time-start)/1000 );
time = await wait(1); console.log('... ' + (time-start)/1000 );
}
console.log('msg#1');
(async () => { await doAsync(); console.log('msg#2'); })();
console.log('msg#3');
async functions are asynchronous!
The function on the penultimate line is going to reach await doAsync();, go to sleep, and the parent function will continue with the next line console.log('msg#3');.
If you want to wait for that async function to finish, you need to await it too.
an answer that I will suggest myself, more a workaround than a true answer..
let's hope we get an even better answer from the community.
(async () => { await doAsync(); console.log('msg#2'); everythingThatFollowsdoAsync(); })();
function everythingThatFollowsdoAsync(){
// let's do here the rest of the code, now that doAsync() is over.
console.log('msg#3');
}
and then I'm getting the expected output:
msg#1
1.002
2.003
msg#2
msg#3
Ok so I am newbie in Angularjs,one of my current task is to code a CRUD functionality and I used the Promise to handle it.
dao.updateEntityCharSpecUseRelSql = function (paramField) {
return new Promise(function (resolve, reject) {
.......
}).catch(err => { reject(err)});// **my PM says, catching error is wrong**
}
module.exports = dao;
First, I thought, catch block is just alright because I am getting it from the Promise object which returns the error if something goes wrong.
But my Pm says, in order to use this, promises should have .then() first.
Is it really a bad practice to use the catch() without then(). What he propose is that instead, I should create a try & catch block inside the Promise() something like
new Promise (function(resolve, reject){
try {
resolve(something)
}catch(err){
reject(err)
}
})
Please enlighten me for this.TIA
Let's do a step back.
When you create a new Promise() you are responsible to handle each success and failure case.
Who is calling your function (and getting your promise) is responsible to handle the response inside a then() callback, if the promise was successfully resolved, or a catch() callback, if the promise was rejected.
So, you don't need to catch your own promise.
Example:
function init() {
getAsyncValues()
.then(function (result) {
// it will do something based on his business logic
})
.catch(function (error) {
// it will do something based on his business logic
});
}
function getAsyncValues() {
return new Promise(function(resolve, reject) {
...
resolve(SOME_VALUES);
...
reject(SOME_ERRORS);
})
}
And if your "promise handler" need to call async task before resolving something, you can wait his resolution like:
const examplePromise = new Promise(fuction (resolve, reject) {
asyncTask() // executing an async task
.then(function(result) {
resolve(result);
})
.catch(function(error) {
reject(error)
});
})
Should HTTPS functions return asynchronous promises like realtime functions have to?
We haven't been returning in HTTPS functions (just using res.status.send etc), and it looks like firebase/function-samples aren't either. But the documentation is slightly ambiguous https://firebase.google.com/docs/functions/terminate-functions .
This works now in the latest Firebase:
exports.asyncFunction = functions.https.onRequest(async (request, response) => {
const result = await someAsyncFunction();
response.send(result);
});
HTTP functions currently do not respect returned promises - they require a sent result in order to terminate normally. If an HTTP function doesn't send a result, it will time out.
All other types of functions require a returned promise in order to wait for asynchronous work to fully complete.
If you don't have any async work to wait for, you can just return immediately.
These are the three cases outlined in the docs.
After much looking around , this is implementation with a Promise worked for me to return a value from a Google Cloud Function where the function needs to make a third-party asynchronous call :
exports.getSomeAccessToken = functions.https.onCall((data, context) => {
var dataStr = JSON.stringify(data, null, '\t');
console.log('ENTER [getSomeAccessToken], got dataStr: ' + dataStr);
return new Promise((resolve, reject) => {
gateway.clientToken.generate({}, function (err, gatewayResponse) {
var result = {
clientToken: gatewayResponse.clientToken
};
var resultStr = JSON.stringify(result, null, '\t');
console.log("resultStr : " + resultStr);
resolve(result);
});
});
});
Your cloud functions should return"end" with either of the following
res.redirect(), res.send(), or res.end()
What they mean by returning promises, is lets imagine you have a cloud function that updated a node in your realtime database, you would like to complete that work before responding to the HTTP request.
Example code
let RemoveSomething = functions.https.onRequest((req, res) => {
cors(req, res, () => {
// Remove something
DoDatabaseWork()
.then(function (result) {
res.status(200).send();
})
.catch(function (err) {
console.error(err);
res.status(501).send();
});
});
});
Update: Added DoDatabaseWork example.
const DoDatabaseWork = function () {
return new Promise(function (resolve, reject) {
// Remove SomeNode
admin.database().ref('/someNode/').remove()
.then(function (result) {
resolve();
})
.catch(function (err) {
console.error(err);
reject();
});
});
}