27

Await is a amazing feature in es7.

However,everytime I use await I found that I have to define a async function and call this function.

Such as

    async function asy(){
        const [resCityGuess,resCityHot,resCityAll]=await Promise.all([
                        this.http.get('api/v1/cities?type=guess'),
                        this.http.get('api/v1/cities?type=hot'),
                        this.http.get('api/v1/cities?type=group')
        ])
        this.cityGuessName=resCityGuess.data.name;
        this.cityGuessId=resCityGuess.data.id;
        this.cityHot=resCityHot.data;
        this.cityAll=resCityAll.data;
    }
    asy.apply(this);

What I want is use await without async function such as

        // the async function definition is deleted
        const [resCityGuess,resCityHot,resCityAll]=await Promise.all([
                        this.http.get('api/v1/cities?type=guess'),
                        this.http.get('api/v1/cities?type=hot'),
                        this.http.get('api/v1/cities?type=group')
        ])
        this.cityGuessName=resCityGuess.data.name;
        this.cityGuessId=resCityGuess.data.id;
        this.cityHot=resCityHot.data;
        this.cityAll=resCityAll.data;
        // without call fn

I think define the function fn and call this fn is repeated sometimes so I want to know is it possible to optimize the situation?

Can I use await without async?

Thank you so much!

a better oliver
  • 26,330
  • 2
  • 58
  • 66
曾志强
  • 281
  • 1
  • 3
  • 6
  • 2
    the answer to your question is no, but if you're only using the function once, you might want to look at IIFE's (Immediately Invoked Function Expression) – Gabe Rogan May 07 '17 at 14:18
  • @GabeRogan I think this is one solution.Thx – 曾志强 May 07 '17 at 14:27
  • _"Await is a amazing feature in es7"_ It's not a feature of ES 7 at all. It's part of ES 2017. – a better oliver May 08 '17 at 07:09
  • 2
    I really wish we could downvote comments, like @JacqueGoupil's. Of course it makes sense: you may want to await the results of a Promise before continuing on, when you are not in control of the code returning the Promise or when it serves a dual purpose. – Andrew Aug 28 '19 at 15:57
  • @Andrew That comment was written before the question was heavily edited and had no mention of promises. Reading back, I'll admit it was a rather harsh way to say I didn't understand the question and needed more info. – Domino Aug 28 '19 at 20:23

5 Answers5

29

No. The await operator only makes sense in an async function.

edit — to elaborate: the whole async and await deal can be thought of as being like a LISP macro. What that syntax does is inform the language interpretation system of what's going on, so that it can in effect synthesize a transformation of the surrounding code into a Promise-based sequence of callback requests.

Thus using the syntax is an implicit short-cut to coding up the explicit Promise stuff, with calls to .then() etc. The runtime has to know that a function is async because then it knows that await expressions inside the function need to be transformed to return Promises via a generator mechanism. And, for overlapping reasons, the async decoration on the function declaration tells the language that this is really a function that returns a Promise and that it needs to deal with that.

So, it's complicated. The process of improving and extending JavaScript has to account for the fact that there's an unimaginably massive amount of JavaScript code out in the world, and so in almost all cases no new feature can cause a page untouched since 2002 to fail.

edit — Now, here in 2021, there are rules for how an await call works in the outer level of a module. It's not quite the same as how it works in an async function situation, but it's similar.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • Thx. I want to use IIFE to help me. – 曾志强 May 07 '17 at 14:29
  • 23
    @曾志强 yes, you can do that: `(async function() { ...; await x(); ... })();` – Pointy May 07 '17 at 14:31
  • 4
    This documentation is super helpful to understand why: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await – craftsman Sep 09 '17 at 14:55
  • @Pointy's answer is the correct solution to this problem. More specifically ```(async() => { await x(); })();``` – DARKGuy Apr 27 '18 at 03:39
  • 1
    Using the example from the mozilla link above, why does this code work without async if I paste it in the console? `function resolveAfter2Seconds(x) { return new Promise(resolve => { setTimeout(() => { resolve(x); }, 2000); }); }; await resolveAfter2Seconds(10);` – Jarrod McGuire May 25 '18 at 10:13
  • @JarrodMcGuire because your function returns a Promise. – Pointy May 25 '18 at 11:12
  • But the example in mozilla has it wrapped inside an additional async function? Is the additional wrapper necessary? Also (please forgive my newness to await/async), although it works for me in a browser, it doesn't work in nodejs – Jarrod McGuire May 25 '18 at 11:55
  • 1
    @JarrodMcGuire well doing things in the console is always a little weird, because whatever provides the console (a browser or Node) has to create some sort of context in which the typed-in code can make syntactic sense. Because of the semantics of `await`, it has to be used inside an `async` function because calling the function involves handling the Promise returned etc. It's "syntactic sugar" around Promise and a trick with generator function behavior. An `await` function call implicitly returns from the calling context the same kind of thing a generator returns. – Pointy May 25 '18 at 11:59
  • 2
    Thanks for your patience @Pointy. Have just read some stuff, and I think I was missing the bit that you need to "async all the way up" (which you just confirmed). await in the global scope works, but in practice you aren't going to have that. I feel that I have somewhat replaced promise/callback hell with async hell, but I will persevere. – Jarrod McGuire May 25 '18 at 12:19
  • 1
    "async hell" was going a bit far. Was a bit frustrated because I couldn't get my head around it for about 2 hours. Think I have mostly have it now. Thanks again – Jarrod McGuire May 25 '18 at 12:51
  • Hey @JarrodMcGuire, this “async all the way up hell” you just described is exactly the problem I’m having as well. Did you, now more than 3 years later, find a solution? – balanceglove2 Nov 04 '21 at 22:28
  • @LeonTepe I don't think I have a solution, maybe just change my mindset. Also, I haven't done too much with promises, just mostly libraries that use promises internally so you can call await where you need or use .then when you don't. I have been working on a bit react with typescript project and have noticed that I haven't doing a lot of "all the way up" stuff, so I wonder if it's taking care of that internally or something. Sorry, that probably doesn't help much. – Jarrod McGuire Nov 12 '21 at 14:19
  • @Pointy it looks like you were conceptually wrong about await. await is a synchronous concept. The fact you could not use it outside of async was just a convention so that application don't freeze while await is doing its job. But that is just a convention, and it totally works when you remove that arbitrary convention (see: top level await). People reading your answer think await is something related to async but it's totally not. Await can be explained without ever mentioning async. – Antoine Weber Jan 16 '22 at 10:51
  • @AntoineWeber no, that is not at all correct. Top-level `await` **is** asynchronous; it's always asynchronous. The use of `await` always introduces a Promise. – Pointy Jan 16 '22 at 13:28
  • @AntoineWeber note also that the answer *does in fact mention* using `await` at module level. – Pointy Jan 16 '22 at 14:06
  • "The await operator only makes sense in an async function." Once we met AWAIT - this means that the function will run in SYNC mode. So, IMHO async keyword in this case is NONSENSE. Or maybe I`m missing something – Dmitry Isakov Feb 06 '23 at 18:44
  • @DmitryIsakov JavaScript **always** _runs_ synchronously. What `async` functions and `await` for asynchronous operations do is making living with the reality of Promise-based asynchronous programming _seem_ like everything is synchronous. It is however not synchronous. – Pointy Feb 06 '23 at 18:56
9

Solution

Not exactly without async but take a look, this may illuminate.

You can effectively create an arrow function (that is intentionally anonymous).

Arrow functions are an ECMAScript2015 syntax for writing anonymous functions. They have a lot of features that separate them from the original function keyword in JavaScript, but in many cases they can be a drop-in replacement for anonymous functions.

Add the async keyword, surround the function with parentheses and add another parentheses set to run the function.

Inside the function, use the await keyword.

Like this:

(async () => {
    console.log("Message in 5s");
    await new Promise((resolve) => setTimeout(() => resolve(), 5000));
    console.log("If you like it, show it");
})();
Stas Sorokin
  • 3,029
  • 26
  • 18
  • 4
    This is actually not a solution to any problem. While this might give impression that async functions are getting called and finishing serially BUT that won't be the case. Effect of above it exactly like calling async function without await keyword. Yes it allows to use await keyword inside non async function but it does not solve the actual problem. – Shahid Roofi Khan Nov 07 '22 at 19:08
5

It's proposed to ECMAScript.

Chrome/Chromium (and anything with an up-to-date V8-based JS engine) has a working implementation that appears to be compliant with the specification.

The proposal itself is at stage 3.

More info:

https://github.com/tc39/proposal-top-level-await

https://v8.dev/features/top-level-await

Chumpocomon
  • 661
  • 1
  • 6
  • 12
2

Top-level await (await without async) is not yet a JavaScript feature.

However, as of version 3.8, it can be used in Typescript.

In order to use it, the following configuration is required (in tsconfig.json):

"module": "esnext" // or "system"
"target": "es2017" // or higher

More information:

https://typescript.tv/new-features/top-level-await-in-typescript-3-8/

treecon
  • 2,415
  • 2
  • 14
  • 28
1

In ES NEXT : new functionality which is called top-level await. It allows developers to use the await keyword without a surrounding async function at the top level of a module.

//use "type" : "module" in package.json

{
  "name": "jsd",
  "version": "1.0.0",
  "type": "module",
  "description": "",
  "main": "j.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
class A {
  constructor() {}

  m() {
    return new Promise((res, rej) => {
      res(true);
    });
  }
}

let r = new A();

//here await can be used without async function wrapper
console.log(await r.m());
Jerry
  • 1,005
  • 2
  • 13