Lets say I have a functin like:
function some(){
console.log("wow")
return "some"
}
var some_test = await some()
console.log(some_test)
I know it works without await but I want to test await . Here it gives unexpected token error.
Why I am unable to use await here ?
The keywords async and await are available in Node.js applications and not yet supported for client side JavaScript. In order to use these keywords, your Node.js application needs to be using the ES7 standards. Here's a nice introduction to the core concepts. Also, here is the official ECMAScript github repo that documents it.
The calling function must be marked as async and then another async method within that call can then be awaited using the await keyword, just like is done in C#. Examples of the syntax are found here.
async function chainAnimationsAsync(elem, animations) {
let ret = null;
try {
for(const anim of animations) {
ret = await anim(elem);
}
} catch(e) { /* ignore and keep going */ }
return ret;
}
Async functions are supported in the latest versions of Chrome and FF already, and according to caniuse, in the upcoming Edge 15. The await keyword can only be used inside a function marked with async. A couple of good tutorials on the subject:
Async Function Documentation from Mozilla
Introduction to Async Functions
Related
basically i have this function
async function get(url){
const response = await fetch(url);
const resData = await response.text();
return resData;
}
then later i have this call
let data = await get(am_url);
the code works perfectly on google chrome, but on firefox, i get this error on the call line :
SyntaxError: await is only valid in async functions and async generators
what's the problem here, for the life of me, i can't seem to make this work on firefox and can't figure out why
for example if i open google.com on firefox and google chrome, then i go to the console, and pase this code, on chrome, it will run, but on firefox, it will throw the error i mentionned
async function get(url){
const response = await fetch(url);
const resData = await response.text();
return resData;
}
let data = await get("http://google.com");
console.log(data)
In main either put your below code in self executing async function or use .then.
let data = await get(am_url);
should be changed to
(async()=>{ let data = await get(am_url) })()
or
get(am_url).then( data => ....)
As the error suggests, await only works inside async functions. Normally you can't use await like that, but you have to create an async function first or use .then() instead of await.
However there are 2 things to be aware of:
The console supports await outside an async function just to simplify your life. Chrome did it first, then Firefox more recently. Your example now works in both browsers.
In a future version of ECMAScript, you will be able to use await outside async functions, it's called "top-level await", so that code will soon work everywhere (in a type="module" context)
In 2018 when this question was asked, most JavaScript consoles did not await at the top level.
At that time, Google Chrome Developer Tools console was the exception. They added the feature in late 2017 in Chrome 62
This is why, in the Firefox version you used when you asked this question, you have to resolve the promise, for example with then/catch.
If you update to a current Firefox, such as version 72 (early 2020), the code in your question will work. As fregante pointed out in a comment, in 2019, Firefox upgraded their console to support top level await.
I am trying to do something like this on global scope in nodejs REPL. As per my understanding both the following statements are valid. see docs
let x = await Promise.resolve(2);
let y = await 2;
However, both these statements are throwing an error.
Can somebody explain why?
my node version is v8.9.4
Update
When using Node, the file currently must have an .mjs extension to work.
Top level awaits can be used in browser modules. When used the script tag must include the type attribute which must be set to module:
<script src="/script.js" type="module"></script>
const start = Date.now()
console.log('Pre call.')
await delayedCall()
console.log('Duration:', Date.now() - start)
function delayedCall() {
return new Promise(resolve => setTimeout(() => resolve(), 2000))
}
Working Node Example -- Run node ./index.mjs in the terminal.
Working Browser Example
Supported Versions
Old Answer
await can only be used within a function that is labeled async, so there are two ways you can approach this.
Note:
There is a proposal in place that may eventually allow the usage of Top level await calls.
The first way is to create a self invoked function like this:
(async function() {
let x = await Promise.resolve(2)
let y = await 2
console.log(x, y)
})()
Or the second way is to use .then()
Promise.resolve(2).then(async data => {
let x = data
let y = await 2
console.log(x, y)
})
This proposal is currently in stage 3 of the TC39 process. LINK
You can use this feature in Google Chrome and Mozilla Firefox as of now. You can use top level await without async in console.
https://twitter.com/addyosmani/status/1080365576218759168
As of version 13.3, Node.js support Top-level await.
Top-level await means you can now use await operator outside an async function. So both examples are correct:
(async function() {
await Promise.resolve(console.log('Hello await!'));
}());
// or
await Promise.resolve(console.log('Hello await!'));
Note: Top-level await only works at the top level of modules. There is no support for classic scripts or non-async functions.
Just keep in mind, that the await operator is used to wait for a Promise. It does NOT matter if you are using an await operator with a value other than a Promise. For example, the name variable in the displayName()` function:
async function displayName() {
const name = await 'unclexo';
console.log(name);
}
displayName(); // outputs 'unclexo'
As the value of the name variable is not a Promise, it converts the value to a resolved Promise, and waits for it. It happens under the hood.
The old behavior
MDN doc says
The await operator is used to wait for a Promise. It can only be used
inside an async function.
since node 10, you can run node process with --experimental-repl-await to allow top level await
https://nodejs.org/api/repl.html#repl_await_keyword
async function getTen() {
return 10;
}
(async () => {
let ten = await getTen();
console.log(ten);
})();
Source: https://javascript.plainenglish.io/5-javascript-interview-questions-to-identify-outstanding-developers-859a71c3d7f
Top-level-await is supported in Node.js version 13.3 or above
Example:
await Promise.resolve(console.log('๐')); // โ ๐
(Though the question is about REPL, a note on running as script file. Set {"type": "module"} package.json or use the file name extension .mjs)
You could wrap all the code in the global scope in an async function.
For example:
// ...global imports...
new Promise (async () => {
// ...all code in the global scope...
}).then()
As far as I can tell, both the spec and the documentation have await as the only reserved keyword out of the async/await feature.
This is further demonstrated by the fact that we can name a variable async:
For example:
var async = 5;
console.log(async) // this is fine
Node (6.10) (also on Repl.it)
Chrome (59)
Firefox (54)
Is it because of backwards compatibility? I'd guess many codebases would use the name async for certain features.
This allows for some strange looking code examples:
async function async() {
var async = 5;
await async;
return async;
}
async().then(console.log)
Infinite recursive promise chain? (Not really important since any function name would allow this, however this code looks additionally confusing)
async function async() {
await async();
}
// stackoverflow (might need to open your console to see the output)
async does not need to be a reserved word, because it can be uniquely identified. The contexts in which it can occur are those such as
async function() { }
async () => { }
obj = { async foo() { } };
All of these could not be parsed in any way other than seeing async as indicating an async function.
On the other hand, await can in theory be used in a statement such as
async function foo() {
await(1);
}
which is ambiguous; is await awaiting the value 1, or is it a function being called with the parameter 1? Therefore, await needs to be a reserved word (inside async functions; outside, feel free to use it as a variable).
Remember that JavaScript has evolved greatly since its origin. Many words were designated as reserved, and then never used, or designated as reserved when technically they might not need to have been. The designation of await as a reserved word (within modules), and the non-designation of async as a reserved word, are the product of a more mature understanding of the language on the part of its designers.
I was attempting to chain two async functions together, because the first had a conditional return parameter that caused the second to either run, or exit the module. However, I've found odd behavior I can't find in the specs.
async function isInLobby() {
//promise.all([chained methods here])
let exit = false;
if (someCondition) exit = true;
}
This is a bastardized snippet of my code (you can see the full scope here), that simply checks if a player if already in a lobby, but that's irrelevant.
Next we have this async function.
async function countPlayer() {
const keyLength = await scardAsync(game);
return keyLength;
}
This function doesn't need to run if exit === true.
I tried to do
const inLobby = await isInLobby();
This I hoped would await to results, so I can use inLobby to conditionally run countPlayer, however I received a typeerror with no specific details.
Why can't you await an async function outside of the scope of the function? I know it's a sugar promise, so it must be chained to then but why is it that in countPlayer I can await another promise, but outside, I can't await isInLobby?
There is always this of course:
(async () => {
await ...
// all of the script....
})();
// nothing else
This makes a quick function with async where you can use await. It saves you the need to make an async function which is great! //credits Silve2611
Top level await is not supported. There are a few discussions by the standards committee on why this is, such as this Github issue.
There's also a thinkpiece on Github about why top level await is a bad idea. Specifically he suggests that if you have code like this:
// data.js
const data = await fetch( '/data.json' );
export default data;
Now any file that imports data.js won't execute until the fetch completes, so all of your module loading is now blocked. This makes it very difficult to reason about app module order, since we're used to top level Javascript executing synchronously and predictably. If this were allowed, knowing when a function gets defined becomes tricky.
My perspective is that it's bad practice for your module to have side effects simply by loading it. That means any consumer of your module will get side effects simply by requiring your module. This badly limits where your module can be used. A top level await probably means you're reading from some API or calling to some service at load time. Instead you should just export async functions that consumers can use at their own pace.
As of Node.js 14.3.0, the top-level await is supported with a flag:
--experimental-top-level-await
As of Node.js 16.12.0 / 17.0.0, no flag required.
Further details: https://v8.dev/features/top-level-await.
you can do top level await since typescript 3.8
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#-top-level-await
From the post:
This is because previously in JavaScript (along with most other languages with a similar feature), await was only allowed within the body of an async function. However, with top-level await, we can use await at the top level of a module.
const response = await fetch("...");
const greeting = await response.text();
console.log(greeting);
// Make sure we're a module
export {};
Note thereโs a subtlety: top-level await only works at the top level of a module, and files are only considered modules when TypeScript finds an import or an export. In some basic cases, you might need to write out export {} as some boilerplate to make sure of this.
Top level await may not work in all environments where you might expect at this point. Currently, you can only use top level await when the target compiler option is es2017 or above, and module is esnext or system. Support within several environments and bundlers may be limited or may require enabling experimental support.
All version of babel translate an await statement to a _asyncToGenerator call, it obviously has some shortcomings:
Code size grows dramatically
Requires the regeneratorRuntime library
From my understanding of the syntax I think any await should be equivalent to a Promise#then call, so the code below:
try {
let user = await getUser();
console.log(user.name);
}
catch (error) {
console.error(error);
}
is just equivalent to:
let promise$of$getUser$ = getUser();
$promise$of$getUser$.then(
$result$ => console.log($result$),
$error$ => console.error($error$)
);
In this way it is also possible to correctly map multiple await statements or even a mix of Promise#then and await statements to a Promise chain, so I must missed some cases where pure Promise#then is not suitable for await statements.
You can use the other 2 plugins: async-to-generator and async-to-module-method.
There's also an experimental plugin called kneden which does try to do what you are suggesting (async to promise). It's still WIP and doesn't account for all cases and most likely will not be able to.
I think you're overlooking loops:
for (let userId of userIds) {
const user = await getUser(userId);
console.log(user);
}