Javascript - wait for async functions with new async functions - javascript

Question:
Is it possible to wait for an async function that starts new async functions?
Details:
I have looked up a bunch of ways to wait for an async function to finish before continuing the code, or running a specific function or code block. But one thing have bugged me for a very long time - I do not know whether new async functions started are also being waited for, or if they require their own piece of code to be taken into account.
Pseudocode:
var value = 1;
af1();
alert(value);
async function af1(){
af2();
}
async function af2(){
af3();
}
async function af3(){
value = 2;
}
I dont know if this is a good example (or even the right syntax), but picture the async functions as some ajax requests that takes some time to finish. I have a feeling that if you add a jQuery deferred on af1, it will only wait for af1 and ignore af2 and af3. I am also using an external javascript file for some of the functions, and I dont really have control over what new functions are started in there.
So again, is it possible to just wrap all of this into something and run some code after all is done? Or am I mistaken about jQuery's deferred and .done functions??

No, async functions are not awaited when called. They just return a promise.
Inside an async function - that's their advantage - you can explicitly await promises, including those that are returned from other async functions.
Your code should have been written using return values, like this:
(async function() { // neccessary to use await
value = await af1();
alert(value);
}());
af1().then(alert); // or just using promise syntax
async function af1(){
return af2();
}
async function af2(){
return af3();
}
async function af3(){
return 2; // or maybe rather something like
return $.ajax(…);
}
But you don't need return values, you can use await as well for your closure approach:
(async function() {
var value = 1;
await af1();
// ^^^^^
alert(value);
async function af1(){
await af2();
}
async function af2(){
await af3();
}
async function af3(){
value = 2; // or maybe rather something like
value = await $.ajax(…);
}
}())

Use this git js ASync
How to use
Async provides around 20 functions that include the usual 'functional' suspects (map, reduce, filter, each…) as well as some common patterns for asynchronous control flow (parallel, series, waterfall…). All these functions assume you follow the Node.js convention of providing a single callback as the last argument of your async function.
Quick Examples
async.map(['file1','file2','file3'], fs.stat, function(err, results){
// results is now an array of stats for each file
});
async.filter(['file1','file2','file3'], fs.exists, function(results){
// results now equals an array of the existing files
});
async.parallel([
function(){ ... },
function(){ ... }
], callback);
async.series([
function(){ ... },
function(){ ... }
]);
There are many more functions available so take a look at the docs below for a full list. This module aims to be comprehensive, so if you feel anything is missing please create a GitHub issue for it.
Read More

Apart from above examples, look at below code sample. concept of async and wait would be more clear.
async function doWork(){
try {
const response = await makeRequest('facebook'); //using await will wait until the response returned from the makeRequest function
//console.log('Response Received' + response );
const response2 = await makeRequest('google');
//console.log('Response2 Received' + response2 );
} catch(err) {
alert(err);
}
}
function makeRequest(str){
//function body that takes time to process, eg: server call
return "making request to " + str;
}
doWork();

Related

Cannot access javascript variable outside the function

Why can't I access the variable field_count outside of loadData() function?
var field_count;
await loadData();
async function loadData() {
var response = await fetch('/get_data');
var data = await response.json();
field_count = data.field_count;
alert(field_count) // shows correct data
}
alert(field_count) //shows undefined
Here loadData() is an async function, but your alert(field_count) outside of any function is not async. You're doing two await() calls inside the function, which operate asynchronously as you've requested of the language. However, the alert() which is outside the function is operating synchronously. Under most circumstances, that top-level alert() will have run and tried to alert() an undefined value before the two await calls are completed.
Mixing async programming and synchronous programming in this way is fraught with traps and pitfalls. I would recommend until you are comfortable with the ideas of asynchronous code and how it differs from other code, set up the program first then stick to async code working with other async code. Once you are comfortable with both and understand the differences, you can consider using results from async code in sync code, but you'll need to learn about how to use promises or some other synchronization method.
Consider the output of this code.:
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 600);
});
}
var result;
async function asyncCall() {
console.log('calling');
result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}
asyncCall().then(() => {
console.log(result)
});
console.log(result);
That is going to quickly log "calling", then undefined, then wait 600 milliseconds and then log "resolved" and another "resolved" quickly.
This part uses promises to coordinate the async function with the parent program.:
asyncCall().then(() => {
console.log(result)
});
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise explain all this fairly well.

How Mongoose is able to know that I've used await on invoking their function or not? [Edited]

[Old question] How can you know if your function concumer used await on invoking your function or not:
Maybe some magic like this:
function x(){
return new Promise((resolve, reject)=>{
console.log(x.awaitWasCalled) // true
})
}
const a = await x()
I'm asking about that because I've seen Mongoose (a library) is able to detect weather you've called await or not, HERE
Here is what they're saying:
Mixing promises and callbacks can lead to duplicate entries in arrays.
For example, the below code inserts 2 entries into the tags array,
*not just 1.
const BlogPost = mongoose.model('BlogPost', new Schema({
title: String,
tags: [String]
}));
// Because there's both `await` **and** a callback, this `updateOne()` executes twice
// and thus pushes the same string into `tags` twice.
const update = { $push: { tags: ['javascript'] } };
await BlogPost.updateOne({ title: 'Introduction to Promises' }, update, (err, res) => {
console.log(res);
});
How Mongoose for example was able to detect that I'm using await or not?
[EDIT] ******* After sometime, I've noticed that the answers bellow doesn't actually answer my question.
Please before answering my question: please read their comment above, they're saying: " // Because there's both await and a callback, this updateOne() executes twice"
this means: if you didn't use await, and you passed in a callback, this code will be invoked once, BUT if you used await + callback, this code will be invoked twice, therefore: the question is: how they're able to know if I've used await or not?!
Again: This means, if you didn't use await, this is going to invoke once, and if you used await, this is going to get invoked twice.
You've misunderstood what the documentation is saying.
It says that calling then will execute the query (but that passing a callback will also execute the query, so you shouldn't do both at the same time).
await is essentially alternative syntax for calling then (although it seems to do some magic with caching).
They don't detect await, they just have a method named then.
const notAPromiseButThenable = {
then: function () {
console.log("Then called");
return this;
}
};
(async function () {
await notAPromiseButThenable.then(() => null).then(() => null);
})();
How can I detect that await was mentioned before calling my function?
You can't. In fact, the function is called before await "kicks in". These two are the same:
await myFunction();
let result = myFunction();
await result;
await is not a different way to call a function, it simply operates on Promises, which of course are often returned by functions. I.e. it operates on the return value of a function.
How Mongoose for example was able to detect that I'm using await or not?
Are they actually able to detect that? Nothing in the documentation you linked seems to indicate that.
What they (and you) could do is checking whether a callback is passed or not. If one is passed then they shouldn't return a Promise and vice versa. But I guess that's not how they want to design the API.
This means, if you didn't use await, this is going to invoke once, and if you used await, this is going to get invoked twice.
Yes, but not because they detect anything but because await does something with the return value of the function. That's just how await works. So obviously, if you don't use await then the thing that await would do won't happen ;)
Here is an example:
function someFunction(value, callback) {
// Nothing in here does any "await" detection
let array = [];
if (callback) {
array.push(value);
callback(array);
}
return {
then(resolver) {
array.push(value);
resolver(array);
}
}
}
(async function() {
console.log('with await', await someFunction(42, () => {}));
someFunction(42, array => console.log('without await', array));
}());

run functions one by one after each other like async but without async

one of them will connect to php page and get some data and other one of my functions will change some html codes with new data which collected by first function.
for example this is my code :
var $data;
firstFunction(){
$.post("index.php",{},function(data){$data=data;});
}
secondFunction(){
$("body").empty().append($data);
}
firstFunction();
secondFunction();
So in the code in upside if we run this its will start collecting data but before finish collecting data its will run second function which is incorrect and it have to run second function after first function finished some thing like this :
$.when(firstFunction()).done(function(){secondFunction();});
But its not works too and i know there is something called async but i wanna know is there anyway else to do this without changing functions and if its possible give me example with async too pls.
And also i don't want to change functions i mean i know that i can do like this :
var $data;
firstFunction(){
$.post("index.php",{},function(data){$data=data;secondFunction();});
}
secondFunction(){
$("body").empty().append($data);
}
firstFunction();
As you can see in the new code second function will run after first permission finish it job but i can't and i don't want to do like this i want something like async but in other way if its possible because i have many functions and its will take long time to change theme.
Thanks a lot.
You might want to consider using a library like Axios which is promise based, you can use async/await with this method as well as promise chaining. You can bring this into your application using either script tag with a CDN or via NPM/Yarn.
https://github.com/axios/axios
Here is an example with async await:
async function getData(){
async function getPosts(){
try {
const response = await
axios.get('https://jsonplaceholder.typicode.com/posts/1');
return response
} catch (error) {
console.error(error);
}
}
var Posts = await getPosts();
document.getElementById('posts').textContent = JSON.stringify(Posts.data);
async function getComments(){
try {
const response = await
axios.get('https://jsonplaceholder.typicode.com/comments/1');
return response
} catch (error) {
console.error(error);
}
}
var Comments = await getComments();
document.getElementById('comments').textContent =
JSON.stringify(Comments.data);
}
https://jsfiddle.net/Lm2c6r40/
try using async attribute in your script tag:
<script src="demo_async.js" async></script>
scource : https://www.w3schools.com/tags/att_script_async.asp

Is possible to call async function without await keyword? and what happens if we call without await?

I would like to do the following and keep in mind it actually works for me. my question is what happens and Is possible to call async usrs() func from non async componentDidMount() func?
if it is not possible why it is working for me by calling this.usrs(usrs) instead of await this.usrs(usrs);
let outState = {};
class A extends Component{
componentDidMount(){
this.usrs(usrs);
}
getData(usr){
return db.collection('a/'+usr+'/bb').get().then(snap=>{
for(i = snap.docs.length-1; i>=0; i--){
outState[usr] = [...outState[usr], snap.docs[i].data()];
if(i === 0) return outState;
}
return false;
});
}
async usrs(usrs){
let os = {}, data = {};
for(i = usrs.length-1; i>=0; i--){
os = await this.getData(usrs[i]);
if(os){
data = { ...data, ...os };
if (i === 0) {
this.setState({ ...this.state, ...data });
}
}
}
}
}
You only need await if the caller needs to wait for the function to be done, for instance when it needs the result of the function, or when it needs to wait for some state/data change that the function causes. If there is no such dependency, you can just 'fire and forget', by not using the await keyword.
As others mentioned, you could use .then as well, but the basic rule is the same: you do that, when you have something specific to do after the function is done. It can be omitted otherwise.
So concretely: With 'caller', I simply mean the function that calls the async function. In your case that would be componentDidMount. The options are then quite simple:
Keep as is. usrs() will be run in the background completely and componentDidMount will continue running until its end.
Use await, so componentDidMount will wait for the return of usrs().
Use usrs().then(), so componentDidMount can continue, but the code specified in .then() is invoked after usrs() returns, if you need to do something that has to happen after usrs() is done.
We use await when we need to call and wait for async function or Promise
In your case when you call it without await inside your componentDidMount, your function will work but your componentDidMount will not wait for that function to completely finishes.
Also if you don't want to use await and you don't want to wait inside componentDidMount, but you want to get notified when your async function finishes, you can use .then instead. Because async functions returns Promise
Here is your componentDidMount with .then
Notice that in this example this.doSomethingElse will call before the this.usrs is complete, and you only will be notified inside .then about your this.usrs result when it finished:
componentDidMount(){
this.usrs(usrs).then(() => {
// Your functions completely finished
})
.catch(err => {
// There was an error
});
this.doSomethingElse();
}
The async work before the name of the function means that the function always returns a promise, so yes it is possible.
await makes JavaScript wait until the promise is resolved and it pauses when you need to work on the result of that promise.
To understand it better I recommend seeing following page https://javascript.info/async-await
You can call an async function from anywhere.
Async function returns a promise so if you call it like below you can use it as if it was a Promise.
async function example(){
return 10;
}
const returnOfAsync = example()
console.log(returnOfAsync instanceof Promise) // true
returnOfAsync.then((theReturn) => {
console.log(theReturn) // 10
})
Under the hood, an await is simply using a promise (same as a then()), the difference being that it waits for the promise to resolve before continuing execution of the code following it.
So...
Call an async function with await and you will receive the results of the async function after it has completed. Any code that follows the await will execute after the async call returns.
Call an async function without await and you will get a promise as the return value. Code following the await will execute immediately.
If the code that follows the async call requires the value returned from the async call or is dependent on something that happens in the async call, use await. If not, then don't.

How async await internally work?

My question is how execution wait for function result in node.js or v8
environment.
We know, node.js is single thread non blocking I/O environment.
What is internal code and how it work?
Example async function:
async function asyncCall() {
// `getCreditorId` and `getCreditorAmount` return promise
var creditorId= await getCreditorId();
var creditAmount=await getCreditorAmount(creditorId);
}
If you execute this function then first wait for creditorId then call getCreditorAmount using creditorId and again wait from creditor Amount in this async function only.
Instead of async function other execution not wait, that works fine.
Second question
If use promise for this example
getCreditorId().then((creditorId)=>{
getCreditorAmount(creditorId).then((result)=>{
// here you got the result
})
});
My assumption if async await use promise internally then async must must know which varibale use in getCreditorAmount function as parameter.
How it know ?
Might be my question is worthless?
If it has a answer then i want to know the ans.
Thanks for help.
async-await uses Generators to resolve and wait for Promise.
await is asynchronous in async-await, when compiler reach at await it stops executing and push everything into event queue and continue with synchronous code after async function. Example
function first() {
return new Promise( resolve => {
console.log(2);
resolve(3);
console.log(4);
});
}
async function f(){
console.log(1);
let r = await first();
console.log(r);
}
console.log('a');
f();
console.log('b');
Since await is asynchronous thus every other thing before await happens as usual
a
1
2
4
b
// asynchronous happens
3
async/await is just a Generator.
Take a look at these docs if you would like to learn more.
Generators
Async Function

Categories

Resources