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
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 have a cloud function that I would like to run whenever a user performs a set of actions on the web app AND daily at a specified time. In the interest of not duplicating code and future features/bug fixes, I'd like to run both from one function/file.
Any suggestions/references on this flow would be greatly appreciated!
You can write your business logic in one function, that you call from the two Cloud Functions. Something along the following lines, with an asynchronous business logic and the use of async/await:
exports.myFunctionCalledFromTheApp = functions.https.onCall(async (data, context) => {
try {
const result = await asyncBusinessLogic();
return { result: result }
} catch (error) {
// ...
}
});
exports.myFunctionCalledByScheduler = functions.pubsub.schedule('every 24 hours').onRun(async (context) => {
try {
await asyncBusinessLogic();
return null;
} catch (error) {
// ...
return null;
}
});
async function asyncBusinessLogic() {
const result = await anAsynchronousJob();
return result;
}
I have a cloud code from which I call an external function.
The cloud code response is null but the console displays the response
my cloud code ;
Parse.Cloud.define("testccadd", async request => {
try {
var ccaddrequest = {
conversationId: '123456789',
email: 'email#email.com',
};
externalFunction (ccaddrequest, function (err, result) {
console.log(result);
return result;
}) ;
} catch (e) {
console.log("Error");
}
});
console.log (result); shows the values from the external function, but the return result; returns null
how can I get the external function response as response of my cloud code function ?
The problem is that your externalFunction uses a callback to return its result. That is an asynchronous event, meaning that it happens after your cloud functions has been processed.
The cloud function will execute var ccaddrequest... and then call externalFunction but it won't "wait" for externalFunction to call the callback function if it contains asynchronous commands.
So you need to wrap the externalFunction in a Promise (see how to promisify callbacks) and then await the result of it.
Plus you need to return the result of the Promise, so in your code you need to add
Parse.Cloud.define("testccadd", async request => {
try {
var ccaddrequest = {
conversationId: '123456789',
email: 'email#email.com',
};
var result = await externalFunctionPromise(...);
return result;
} catch (e) {
console.log("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();
});
});
}
I have list of data which is in array format for example:
var resultArray = ['a','b','c','d','e'];
I have used this array iteration in my code like this:
var updateArray = [];
_.each(resultArray, function (value, index) {
//execute this function for file uploading..
processMyFunction(value, function (error, success) {
if(error) {
//code to push it in my new array list
updateArray.push({value:value,message:error});
}
else {
//code to push it in my new array list
updateArray.push({value:value,message:error});
}
});
console.log(updateArray)
});
Here it does not gives me updated console. As uploading function takes time to do it's action and it come out from this processMyFunction function.
How should i make this _.each to wait until my function does not complete it's process?
Any suggestion on that?
How about using async/await in combination with reduce?
With ES7 this should be possible.
e.g.
updateArray = await updateArray.reduce(async (acc, value) => {
acc = await acc;
await processMyFunction(value, function (error, success) {
if(error) {
//code to push it in my new array list
acc.push({value:value,message:error});
}
else {
//code to push it in my new array list
acc.push({value:value,message:error});
}
});
return acc;
}, []);
console.log(updateArray);
UPDATE
After I did some research on this, I also found this interesting post.