What is the difference between the two functions ?
function src() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(console.log("done! 1 ")), 4000);
});
}
async function src() {
setTimeout(() => console.log("done! 1 "), 4000);
}
The second one will return a Promise that resolves immediately.
The first one will return a Promise that resolves after 4 seconds.
In the first one, once the function is called a promise is returned with resolved state set in a timeout. So when the 4 sec timer ends (ofc without any errors) the resolved function triggers with text logged to the console.
Second one will too return a promise but of no certain use. On being called, it will just trigger the timer to print text after 4 sec. No promise functionality is used here.
Async/Await is just syntactic sugar for promises. Async/Await implicitly uses Promises. Async/Await just makes working with Promises easier.
That being said, your second functions doesn't make use of Async/Await properly. There's no await statement, but it's impossible to use an await statement directly with setTimeout anyway.
So, if you still want to use Async/Await you would have to write your own timeout function that would resemble your first function.
function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function src() {
await timeout(4000);
console.log("done! 1 ");
}
Whenever you create new Promise you get to parameters resolve & reject. Whenever its success case you resolve on failure you reject. In case of resolve it will go to then & in case of reject it will go to catch. Promise is more over like real world promise (it could either be completed [resolved] or broken [reject]).
Though async & await helps you do asynchronous operations in JS. Whenever in async function it encounters await it will wait for that code to be executes and then will move to next line.
Refer to this video for better understanding along with example.
Related
I'm doing some unit testing. The test framework loads a page into an iFrame and then runs assertions against that page. Before each test begins, I create a Promise which sets the iFrame's onload event to call resolve(), sets the iFrame's src, and returns the promise.
So, I can just call loadUrl(url).then(myFunc), and it will wait for the page to load before executing whatever myFunc is.
I use this sort of pattern all over the place in my tests (not just for loading URLs), primarily in order to allow changes to the DOM to happen (e.g. mimick clicking a button, and wait for divs to hide and show).
The downside to this design is that I'm constantly writing anonymous functions with a few lines of code in them. Further, while I have a work-around (QUnit's assert.async()), the test function that defines the promises completes before the promise is run.
I'm wondering if there is any way to get a value from a Promise or wait (block/sleep) until it has resolved, similar to .NET's IAsyncResult.WaitHandle.WaitOne(). I know JavaScript is single-threaded, but I'm hoping that doesn't mean that a function can't yield.
In essence, is there a way to get the following to spit out results in the correct order?
function kickOff() {
return new Promise(function(resolve, reject) {
$("#output").append("start");
setTimeout(function() {
resolve();
}, 1000);
}).then(function() {
$("#output").append(" middle");
return " end";
});
};
function getResultFrom(promise) {
// todo
return " end";
}
var promise = kickOff();
var result = getResultFrom(promise);
$("#output").append(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"></div>
I'm wondering if there is any way to get a value from a Promise or
wait (block/sleep) until it has resolved, similar to .NET's
IAsyncResult.WaitHandle.WaitOne(). I know JavaScript is
single-threaded, but I'm hoping that doesn't mean that a function
can't yield.
The current generation of Javascript in browsers does not have a wait() or sleep() that allows other things to run. So, you simply can't do what you're asking. Instead, it has async operations that will do their thing and then call you when they're done (as you've been using promises for).
Part of this is because of Javascript's single threadedness. If the single thread is spinning, then no other Javascript can execute until that spinning thread is done. ES6 introduces yield and generators which will allow some cooperative tricks like that, but we're quite a ways from being able to use those in a wide swatch of installed browsers (they can be used in some server-side development where you control the JS engine that is being used).
Careful management of promise-based code can control the order of execution for many async operations.
I'm not sure I understand exactly what order you're trying to achieve in your code, but you could do something like this using your existing kickOff() function, and then attaching a .then() handler to it after calling it:
function kickOff() {
return new Promise(function(resolve, reject) {
$("#output").append("start");
setTimeout(function() {
resolve();
}, 1000);
}).then(function() {
$("#output").append(" middle");
return " end";
});
}
kickOff().then(function(result) {
// use the result here
$("#output").append(result);
});
This will return output in a guaranteed order - like this:
start
middle
end
Update in 2018 (three years after this answer was written):
If you either transpile your code or run your code in an environment that supports ES7 features such as async and await, you can now use await to make your code "appear" to wait for the result of a promise. It is still programming with promises. It does still not block all of Javascript, but it does allow you to write sequential operations in a friendlier syntax.
Instead of the ES6 way of doing things:
someFunc().then(someFunc2).then(result => {
// process result here
}).catch(err => {
// process error here
});
You can do this:
// returns a promise
async function wrapperFunc() {
try {
let r1 = await someFunc();
let r2 = await someFunc2(r1);
// now process r2
return someValue; // this will be the resolved value of the returned promise
} catch(e) {
console.log(e);
throw e; // let caller know the promise was rejected with this reason
}
}
wrapperFunc().then(result => {
// got final result
}).catch(err => {
// got error
});
async functions return a promise as soon as the first await is hit inside their function body so to the caller an async function is still non-blocking and the caller must still deal with a returned promise and get the result from that promise. But, inside the async function, you can write more sequential-like code using await on promises. Keep in mind that await only does something useful if you await a promise so in order to use async/await, your asynchronous operations must all be promise-based.
If using ES2016 you can use async and await and do something like:
(async () => {
const data = await fetch(url)
myFunc(data)
}())
If using ES2015 you can use Generators. If you don't like the syntax you can abstract it away using an async utility function as explained here.
If using ES5 you'll probably want a library like Bluebird to give you more control.
Finally, if your runtime supports ES2015 already execution order may be preserved with parallelism using Fetch Injection.
Another option is to use Promise.all to wait for an array of promises to resolve and then act on those.
Code below shows how to wait for all the promises to resolve and then deal with the results once they are all ready (as that seemed to be the objective of the question); Also for illustrative purposes, it shows output during execution (end finishes before middle).
function append_output(suffix, value) {
$("#output_"+suffix).append(value)
}
function kickOff() {
let start = new Promise((resolve, reject) => {
append_output("now", "start")
resolve("start")
})
let middle = new Promise((resolve, reject) => {
setTimeout(() => {
append_output("now", " middle")
resolve(" middle")
}, 1000)
})
let end = new Promise((resolve, reject) => {
append_output("now", " end")
resolve(" end")
})
Promise.all([start, middle, end]).then(results => {
results.forEach(
result => append_output("later", result))
})
}
kickOff()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Updated during execution: <div id="output_now"></div>
Updated after all have completed: <div id="output_later"></div>
I know an async function returns a Promise, so I thought of replacing this code:
const hi = function (delay) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('hi');
resolve();
},delay)
});
};
const bye = async () => {
await hi(1000);
await hi(1000);
await hi(1000);
await hi(1000);
return 'bye';
};
bye().then((msg) => {
console.log(msg);
});
with this code:
const hi = async (delay) => {
setTimeout(() => {
console.log('hi');
},delay);
};
const bye = async () => {
await hi(1000);
await hi(1000);
await hi(1000);
await hi(1000);
return 'bye';
};
bye().then((msg) => {
console.log(msg);
});
The only difference is I'm using an async function instead of a function which returns a Promise, since an async function return a promise. But the second code doesn't work as I expected it too. It just console.logs bye immediately and then after 1s console.logs 'hi' 4 times. Can you please help me understand the reason behind this?
One major difference in both code examples is related to the return value of hi function.
In the first code example, function hi returns a promise whereas in the second code example, function hi does not explicitly returns any value; as a result, the promise returned by the async function is implicitly resolved with the value of undefined without waiting for the setTimeout's callback function to execute.
A promise object doesn't makes anything asynchronous; its just a wrapper around an already asynchronous operation and the promise object notifies whether the asynchronous operation completed successfully or whether it failed.
In the first code example, you have a wrapper promise around the setTimeout. That wrapper promise is not fulfilled until resolve is called from within the callback function of the setTimeout.
In the second code example, the promise returned by the async function isn't automatically bound to the asynchronous code inside the function.
After calling setTimeout, code execution reaches the end of the hi function; As there is no explicit return statement, promise returned by the async function is fulfilled with the value of undefined. This happens before the callback function of the setTimeout is called.
What's confusing you here is the setTimeout, your await hi( will actually await, but there isn't anything to wait for, that promise will almost immediately resolve and return so all 4 of them will execute almost instantaneously, then log "bye", then after 1 second your timeout will trigger and console.log "hi".
This answer adds some additional info to the one provided by Yousaf.
To shortly answer your comment:
Thanks for the explanation. Is there any way to write the hi function without using the 'Promise' keyword?
The answer is no. To convert a function using a callback interface to one that uses a promise you will have to manually create a promise somewhere. Functions using an older interface (usually) don't return promises, therefore you cannot await them. You can only await objects that are thenable (i.e. has a "then" method). If you await a non-thenable value or object, the await statement is essentially ignored.
MDN recommends wrapping callback methods at the lowest level possible:
Creating a Promise around an old callback API
A Promise can be created from scratch using its constructor.
This should be needed only to wrap old APIs.
In an ideal world, all asynchronous functions would already return
promises. Unfortunately, some APIs still expect success and/or failure
callbacks to be passed in the old way. The most obvious example is the
setTimeout() function:
setTimeout(() => saySomething("10 seconds passed"), 10*1000);
Mixing old-style callbacks and promises is problematic. If
saySomething() fails or contains a programming error, nothing
catches it. setTimeout is to blame for this.
Luckily we can wrap setTimeout in a promise. Best practice is to
wrap problematic functions at the lowest possible level, and then
never call them directly again:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
wait(10*1000).then(() => saySomething("10 seconds")).catch(failureCallback);
Basically, the promise constructor takes an executor function that
lets us resolve or reject a promise manually. Since setTimeout()
doesn't really fail, we left out reject in this case.
If you would apply this info to your situation, this means wrapping the setTimeout() call within a Promise constructor like shown above.
// The only responsibility of this function is converting the old
// callback interface, to a promise interface.
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
Then use this new function in hi() instead of setTimeout().
async function hi(delay) {
await wait(delay);
console.log('hi');
}
A promise captures the result of an asynchronous processing that just started.
On the version of the code without promises, the asynchronous processing happens the same way as on the first version but there is nobody there waiting for it when it completes.
The second version of the hi() function is synchronous. It completes immediately. The async keyword does not have any effect on it. Also await hi() does not help, the function is still synchronous and it completes immediately.
I am new to JS and was learning promises. So, let's say we have this code:
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) { // (**)
alert(result); // 1
return result * 2;
})
As you can see the code above, when promise is invoked, setTimeout is run via callback queue. The question is When setTimeOut is sent to a browser, will JS engine omit .then() and continues running the rest of the code until the promise resolves? Secondly, async/await example:
async function showAvatar() {
// read our JSON
let response = await fetch('/article/promise-chaining/user.json');
let user = await response.json();
// read github user
let githubResponse = await fetch(`https://api.github.com/users/${user.name}`);
let githubUser = await githubResponse.json();
// show the avatar
let img = document.createElement('img');
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.append(img);
// wait 3 seconds
await new Promise((resolve, reject) => setTimeout(resolve, 3000));
img.remove();
return githubUser;
}
showAvatar();
When showAvatar function is called, JS engine will encounter let response = await fetch('/article/promise-chaining/user.json'); and sends fetch to the browser to handle. The second question is Will JS engine wait until fetch gets resolved or Will JS engine continue executing let user = await response.json(); and the rest of the code inside showAvatar function? If so, how can JS engine handle response.json() since response is not received? Hope you got my point))).
Your first example works like this:
new Promise runs, calling the function you pass it (the executor function) synchronously
Code in the executor function calls setTimeout, passing in a function to call 1000ms later; the browser adds that to its list of pending timer callbacks
new Promise returns the promise
then is called, adding the function you pass into it to the promise's list of fulfillment handlers and creating a new promise (which your code doesn't use, so it gets thrown away).
1000ms or so later, the browser queues a call to the setTimeout callback, which the JavaScript engine picks up and runs
The callback calls the resolve function to fulfill the promise with the value 1
That triggers the promise's fulfillment handlers (asynchronously, but it doesn't really matter for this example), so the handler attached in Step 4 gets called, showing the alert and then returning result * 2 (which is 1 * 2, which is 1). That value is used to fulfill the promise created and thrown away in Step 4.
Will JS engine wait until fetch gets resolved or Will JS engine continue executing let user = await response.json();...
It waits. The async function is suspended at the await in await fetch(/*...*/), waiting for the promise fetch returned to settle. While it's suspended, the main JavaScript thread can do other things. Later, when the promise settles, the function is resumed and either the fulfillment value is assigned to response (if the promise is fulfilled) or an exception will get thrown (if it is rejected).
More generally: async functions are synchronous up until the first await or return in their code. At that point, they return their promise, which is settled later based on the remainder of the async function's code.
In a comment you asked:
when async function is suspended at each await, will async function is removed from the call stack and is put back to the call stack again when the promise being awaited settles?
At a low level, yes; but to make debugging easier, a good, up-to-date JavaScript engine maintains an "async call stack" they use for error traces and such. For instance, if you run this on Chrome...
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function inner() {
await delay(80);
throw new Error("boom");
}
async function outer() {
await inner();
}
function wrapper() {
outer()
.then(result => {
console.log(result);
})
.catch(error => {
console.log(error.stack);
});
}
wrapper();
...the stack looks like this:
Error: boom
at inner (https://stacksnippets.net/js:18:11)
at async outer (https://stacksnippets.net/js:22:5)
Notice the "async" prior to "outer," and also notice that wrapper isn't mentioned anywhere. wrapper is done and has returned, but the async functions were suspended and resumed.
I've tried to understand Promise
from google source, and haven't found how it execute code asynchronously.
My understanding of asynchronous function is that code below it can be resolved at a time before it.
For example:
setTimeout(()=>{console.log("in")}, 5000);
console.log("out");
// output:
// out
// in
The second line fufilled before the first line , so I think setTimeout is an asynchronous tech. But see this code of Promise:
let p = new Promise((resolve, reject)=>{console.log('in'); resolve(1);});
console.log("out");
//in
//out
This code block is actually excuted line by line, if console.log('in'); is a time-consuming operation, the second line will be blocked until it's resolved.
We usually use Promise like this:
(new Promise(function1)).then(function2).then(function3)
Does this mean: Promise is just used to promise that function2 is executed after function1, it's not a tech to realize asynchronous ,but a method to realize synchronous (function1, function2, function3 are executed sequently).
A promise is just a way to describe a value that does not exist yet, but will arrive later. You can attach .then handlers to it, to get notified if that happens.
Does this mean: Promise is just used to promise that function2 is executed after function1?
Yes exactly, even if function1 returns it's value asynchronously (through a Promise), function2 will run only if that value is present.
it's not a tech to realize 'asynchronous' but a method to realize 'synchronous' [execution] ?
Not really. It makes little sense to wrap a value that already exists into a promise. It makes sense to wrap a callback that will call back "asynchronously" into a promise. That said, the Promise itself does not indicate wether the value it resolves to was retrieved in a synchronous or asynchronous maner.
function retrieveStuffAsynchronously() {
// direclty returns a Promise, which will then resolve with the retrieved value somewhen:
return new Promise((resolve, reject) => {
// directly executes this, the async action gets started below:
setTimeout(() => { // the first async code, this gets executed somewhen
resolve("the value"); // resolves asynchronously
}, 1000);
});
}
console.log(retrieveStuffAsynchronously()); // does return a promise immeadiately, however that promise is still pending
retrieveStuffAsynchronously().then(console.log);
Sidenote: However, Promises are guaranteed to resolve asynchronously:
const promise = new Promise((resolve, reject)=>{
console.log('one');
resolve('three');
});
promise.then(console.log); // guaranteed to be called asynchronously (not now)
console.log("two");
I am learning about Javascript ES2017 async/await feature.
Been reading a lot about it, and came across an understanding that await is like yield, and allows us to wait for the promises to complete.
From https://javascript.info/async-await
async function showAvatar() {
// read our JSON
let response = await fetch('/article/promise-chaining/user.json');
let user = await response.json();
// read github user
let githubResponse = await fetch(`https://api.github.com/users/${user.name}`);
let githubUser = await githubResponse.json();
// show the avatar
let img = document.createElement('img');
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.append(img);
// wait 3 seconds
await new Promise((resolve, reject) => setTimeout(resolve, 3000));
img.remove();
return githubUser;
}
showAvatar();
The question I have is, can I add await to every single line of code?
Or what happens if I remove the word await?
And another question is, if async/ await makes the code seems to run synchronously and in order, why don't we don't use it at all (means make everything stay synchronous in the first place?)
Thank you!
async functions are just syntactic sugar around Promises. It does nothing to change the function to be synchronous. In fact any function that is async implicitly returns a Promise object.
All await does is provide a convenient way to wait for a Promise. If you remove the await keyword, then the Promise will not be "unwrapped," which is not what you want if your function is going to operate on the result of that Promise.
To illustrate, this is the desugared version of your async function:
function showAvatar() {
let githubUser;
// read our JSON
return fetch('/article/promise-chaining/user.json').then(response => {
return response.json();
}).then(user => {
// read github user
return fetch(`https://api.github.com/users/${user.name}`);
}).then(githubResponse => {
return githubResponse.json();
}).then(user => {
githubUser = user;
// show the avatar
let img = document.createElement('img');
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.append(img);
// wait 3 seconds
return new Promise((resolve, reject) => setTimeout(resolve, 3000));
}).then(() => {
img.remove();
return githubUser;
});
}
So await essentially just adds a .then callback to a Promise. Without await being specified, you'll just have a Promise object, not the result of the Promise.
await tells the runtime to wait for the promise returned from the expression on the right-hand side to be fulfilled.
In the following code control is stopped in the async function until the promise returned by the fetch invocation is fulfilled, and the response value sent to the fulfilled promise is printed to the console.
async function go() {
let response = await fetch('http://www.example.com');
console.log(response); // print the response after some time
}
go();
If the await keyword was omitted then control would immediately continue to the next line of the function and the the promise returned by fetch would be immediately printed to the console.
async function go() {
let response = fetch('http://www.example.com');
console.log(response); // print the promise from fetch immediately
}
go();
await is a contextual keyword that only means something special when used inside a function marked async. By marking a function async you are telling the runtime to:
treat the function as a generator function
yield a value where the user types await (usually a promise)
wrap the function in special handling logic so that progress through the function only occurs when each promise yielded by await is fulfilled
In this way, asynchronous control flows can be written in a style closer to the traditional synchronous style. ie. without nesting, callbacks or visible promises. try..catch can also be used in the normal way.
As another answer mentions, async, and await are syntactic sugar that ask the runtime to use existing objects (generator functions and Promises) behind the scenes to make async code easier to read and write.
can you await every line
I would guess you can. If the expression on the right of the await results in a promise, then the async/await behaviour detailed above occurs.
If the expression on the right of the await does not result in a promise, then I would guess the value is wrapped in a resolved promise for you, and logic continues per the above, as though the value came from an immediately resolved promise. This is a guess.
First, async / await, work with promises. If you are not calling from an async function or the await sentence is not then compatible, it won't work. In most cases if you remove await, you are going to end with a Promise and not the value of the promise.
Secondly, there are some cases that you may want to continue with the execution of the code while you are resolving some asynchronous task.