0

Node 7.9.0

This is the scenario:

class TestClass {
  constructor() {
    const x = await this.asyncFunc()
    console.log(x)
  }
  async asyncFunc() {
    return new Promise((accept) => {
      setTimeout(() => accept("done"), 1000)
    })
  }
}
new TestClass()

The error is Unexpected token this on line 3

OK, so I wrap it up like this... const x = await (this.asyncFunc())

Now I get await is not defined

It makes me think that node 7.9.0 has no idea about await/sync despite http://node.green/ telling me it is supported and it's example is running just fine.

(function(){
(async function (){
  await Promise.resolve();
  var a1 = await new Promise(function(resolve) { setTimeout(resolve,800,"foo"); });
  var a2 = await new Promise(function(resolve) { setTimeout(resolve,800,"bar"); });
  if (a1 + a2 === "foobar") {
    console.log("passed")
  }
}());
})()
Jake Cattrall
  • 461
  • 4
  • 20
  • 1
    Note that in the example, `await` is used inside an `async` function. Your code is different in that respect. – Pointy Apr 17 '17 at 12:53
  • ... so you need an async constructor... – Jonas Wilms Apr 17 '17 at 12:54
  • See [this question](http://stackoverflow.com/questions/42701963/use-await-outside-async?rq=1). – Pointy Apr 17 '17 at 12:54
  • You cannot use `await` in a constructor. However, you could do `this.asyncFunc().then(console.log)`. In general async processing in constructors should be avoided, however. –  Apr 17 '17 at 13:00
  • You might want to check [this](http://stackoverflow.com/questions/33879401/es6-class-es7-async-await-getter]) out. – haipham23 Apr 17 '17 at 13:17

2 Answers2

1

Adding an async start function and using that fixes the issue:

So the initial example can be fixed with an async start function:

class TestClass {
  constructor() {
    this.start()
  }
  async start() {
    const x = await this.asyncFunc1()
    console.log(x)
  }
  async asyncFunc1() {
    return new Promise((accept) => {
      setTimeout(() => accept("done"), 1000)
    })
  }
}
new TestClass()

If you want to call further awaits inside the asyncFunc1 you need to make the promise function async too...

class TestClass {
  constructor() {
    this.start()
  }
  async start() {
    const x = await this.asyncFunc1()
    console.log(x)
  }
  async asyncFunc1() {
    return new Promise(async (accept) => {
      const x = await this.asyncFunc2()
      accept(x)
    })
  }
  async asyncFunc2() {
    return new Promise((accept) => {
      accept("done")
    })
  }
}
new TestClass()
Jake Cattrall
  • 461
  • 4
  • 20
  • Thing is the object is constructed and it's reference returned to the caller without waiting while the start function runs. For example the caller might start using other member functions that were not ready. It's better imo to have the constructor initialize the object (i.e. with default or passed in values) and let the caller call 'start(..)' themselves. – Craig Allen Apr 17 '17 at 22:25
-1

IMHO it is not wise to use an await in a constructor. Constructors should be lightweight. Constructors should not fail.

MSDN about constructors

Consider providing simple, ideally default, constructors. A simple constructor has a very small number of parameters, and all parameters are primitive types or enumerations.

Consider using a static factory method instead of a constructor if the semantics of the desired operation do not map directly to the construction of a new instance, or if following the constructor design guidelines feels unnatural.

A good solution would be to create a static async factory method that would call a simple private constructor and call your private asyncfunc.

This way, the only way people could create an instance of your class by calling your static async factory method, and thus you would be certain that your asyncFunc has been called.

And the nice thing is: it is all without trickery

I'm not really familiar with JAVA, the following is in C#, but I guess you'll get the idea

class TestClass
{
    public async Task<TestClass> CreateAsync()
    {
        TestClass instance = new TestClass(); // lightWeight
        Promise p = await instance.AsyncFunc();
        // do what you need to do with your Promise
        Console.Log(...)
        return instance;
    }

    // private constructor: only CreateAsync can call it:
    private TestClass()
    {
        // make it lightweight
    }

    public async Task<Promise> AsyncFunc()
    {
        return new Promise((accept) => 
        {
            setTimeout(() => accept("done"), 1000)
        });
    }
}

Usage.

Instead of

TestClass myObject = new TestClass();

you'd do:

 TestClass myObject = await TestClass.Creat();

Your call will be async, the constructor lightweight and you are certain that your asyncFunc is called and awaited for.

Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116