Can async/await be used in constructors? [duplicate]
Asked Answered
S

4

34

As the question stated. Will I be allowed to do this:

class MyClass {
    async constructor(){
        return new Promise()
    }
}
Socialize answered 1/4, 2016 at 18:21 Comment(5)
async/await is not part of ES7.Preparator
Even if it would be possible (hint: it's not), it would be a horrible practiceBraided
A possible solution would be to add a static async function that does the asynchronous initialization prior to actually constructing the instance of MyClass.Gyre
@Braided - luckily real world code makes these questions relevant anywayRaper
Does this answer your question? Async/Await Class ConstructorMaurinemaurise
O
16

Without trying to fortune-tell about future decisions, let's concentrate on practicality and what is already known.

ES7, like ES6 before it will try to be a backwards compatible expansion to the language. With that in mind, a backwards compatible constructor function is essentially a regular function (with some runtime restrictions) that's meant to be invoked with the new keyword. When that happens, the function's return value gets special treatment, specifically, non-object return values are ignored and the newly allocated object is returned while object return values are returned as is (and the newly allocated object is thrown away). With that, your code would result in a promise being returned and no "object construction" would take place. I don't see the practicality of this and I suppose if anybody takes the time to find what to do with such code it will be rejected.

Omaromara answered 1/4, 2016 at 18:32 Comment(5)
Makes sense. It isn't clear in the proposal. I was wondering it because you can still use a return value in the constructor so you won't receive your instance.Socialize
I didn't really get the chance to go through the proposal hence my hypothetical answer, but I'm fairly confident this will be defined as static code error.Omaromara
If they were to add it, I think they would also have to add some way of defining an async class so that you would know to await the constructor function (which sounds tacky) in order to get around the issue that Amit presents.Subcartilaginous
I don't get the (and the newly allocated object is thrown away) part. Any article ref or spec ref?Tribrach
@AnubhavSaini - I meant the object is not referenced by any variable, is inaccessible, and is later garbage collected. The language spec is publicly available.Omaromara
S
69

To expand upon what Patrick Roberts said, you cannot do what you are asking, but you can do something like this instead:

class MyClass {
  constructor() {
     //static initialization
  }

  async initialize() {
     await WhatEverYouWant();
  }

  static async create() {
     const o = new MyClass();
     await o.initialize();
     return o;
  }
}

Then in your code create your object like this:

const obj = await MyClass.create();
Shinshina answered 29/11, 2017 at 18:0 Comment(1)
Thanks for answering the spirit of the question instead of just saying, "No, it's not allowed."Strychninism
O
16

Without trying to fortune-tell about future decisions, let's concentrate on practicality and what is already known.

ES7, like ES6 before it will try to be a backwards compatible expansion to the language. With that in mind, a backwards compatible constructor function is essentially a regular function (with some runtime restrictions) that's meant to be invoked with the new keyword. When that happens, the function's return value gets special treatment, specifically, non-object return values are ignored and the newly allocated object is returned while object return values are returned as is (and the newly allocated object is thrown away). With that, your code would result in a promise being returned and no "object construction" would take place. I don't see the practicality of this and I suppose if anybody takes the time to find what to do with such code it will be rejected.

Omaromara answered 1/4, 2016 at 18:32 Comment(5)
Makes sense. It isn't clear in the proposal. I was wondering it because you can still use a return value in the constructor so you won't receive your instance.Socialize
I didn't really get the chance to go through the proposal hence my hypothetical answer, but I'm fairly confident this will be defined as static code error.Omaromara
If they were to add it, I think they would also have to add some way of defining an async class so that you would know to await the constructor function (which sounds tacky) in order to get around the issue that Amit presents.Subcartilaginous
I don't get the (and the newly allocated object is thrown away) part. Any article ref or spec ref?Tribrach
@AnubhavSaini - I meant the object is not referenced by any variable, is inaccessible, and is later garbage collected. The language spec is publicly available.Omaromara
T
16

In a nutshell:

  1. Constructor is a function that needs to provide a concrete object.
  2. Async returns a promise; exactly opposite of concreteness.
  3. async constructor is conceptually conflicting.
Tribrach answered 8/4, 2016 at 4:57 Comment(0)
N
9

You can get a promise from the return value, and await on that:

class User {
  constructor() {
    this.promise = this._init()
  }
  
  async _init() {
    const response = await fetch('https://jsonplaceholder.typicode.com/users')
    const users = await response.json()
    this.user = users[Math.floor(Math.random() * users.length)]
  }
}

(async () {
  const user = new User()
  await user.promise
  return user
})().then(u => {
  $('#result').text(JSON.stringify(u.user, null, 2))
}).catch(err => {
  console.error(err)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre id="result"><code></code></pre>
Narayan answered 2/1, 2018 at 22:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.