0

I am experimenting with async/await, I can't understand why this line :

resolvedValue = await this.tryToSolve()

gives me this error :

Unexpected token this

class Test {

 constructor() {
  this.method = 0
  this.checkLink()
 }

 async checkLink() {
  return new Promise((resolve, reject) => {

   let resolvedValue

   for (let i = 0; i < 3; i++) {
    this.method = i
    resolvedValue = await this.tryToSolve()
    if (resolvedValue) break
   }
   console.log(`Method ${this.method} did the trick.`);
   resolve(resolvedValue)
  })
 }

 tryToSolve() {
  return new Promise((resolve, reject) => { // Resolves if this.method==1
   console.log(`Trying to solve with method ${this.method}...`);
   setTimeout(() => {
    resolve(!!this.method ? `http://www${this.method}.someurl.com` : false)
   }, 1000)
  })
 }
}

const test = new Test()

Does anyone know the correct syntax to store the result of an async method in a variable?

Thanks in advance.

Jeremy Thille
  • 26,047
  • 12
  • 43
  • 63
  • You are awaiting inside an arrow function (you are crossing the boundary between async function and arrow function) – MinusFour Oct 04 '17 at 13:21
  • Precisely. `this` should work inside an arrow function (it should refer to the Class), so, what's the problem? Or rather, what's the solution? – Jeremy Thille Oct 04 '17 at 13:23
  • `this` should work, but not `await`, because `await` doesn't work inside normal arrow functions. You can't just `await` because the body of the function is inside an async function. You can't cross function boundaries. – MinusFour Oct 04 '17 at 13:30
  • 1
    @Mörre As I said, I'm experimenting. This means, trying to get a better understanding. Instead of criticising my obvious lack of understanding, perhaps you could guide me to the solution instead, thanks. – Jeremy Thille Oct 04 '17 at 13:35
  • @JeremyThille Check out this blog and its posts on promises (see the archive): http://2ality.com -- The author also has a free book about ES6. – Mörre Oct 04 '17 at 13:38

2 Answers2

3

To keep things simple, it happens because when you create a Promise, in its' constructor you pass an arrow function, which contains await call. You must always put async keyword before the declaration of a function, that contains await.

So, instead of doing this

async checkLink() {
    return new Promise((resolve, reject) => {

        let resolvedValue

        for (let i = 0; i < 3; i++) {
            this.method = i
            resolvedValue = await this.tryToSolve()
            if (resolvedValue) break
        }
        console.log(`Method ${this.method} did the trick.`);
        resolve(resolvedValue)
    })
}

Do it like this

checkLink() {
    return new Promise(async (resolve, reject) => {

        let resolvedValue

        for (let i = 0; i < 3; i++) {
            this.method = i
            resolvedValue = await this.tryToSolve()
            if (resolvedValue) break
        }
        console.log(`Method ${this.method} did the trick.`);
        resolve(resolvedValue)
    })
}

More info: https://ponyfoo.com/articles/understanding-javascript-async-await#using-async-await

vanelizarov
  • 1,064
  • 1
  • 8
  • 24
  • Why would you create a new promise??? Only to then create yet another promise in the inner function? Declare the outer function `async` and remove the `new Promise`. It already returns one! And the `async` allows the `await`. Instead or `resolve` use `return`. – Mörre Oct 04 '17 at 13:36
  • Because my ultimate architecture goal is a main Promise that will get resolved when all the sub-promises are resolved. Feel free to demonstrate your knowledge with a snippet in another answer :) – Jeremy Thille Oct 04 '17 at 13:39
  • If you have multiple promises you use `Promise.all` after creating them all in parallel. – Mörre Oct 04 '17 at 13:40
  • @vanelizarov That was it, thanks. It became clear and obvious when I saw the solution. – Jeremy Thille Oct 04 '17 at 13:40
  • 1
    @JeremyThille This is NOT a solution. It is a promise inside a promise, just ridiculous. – Mörre Oct 04 '17 at 13:41
  • You keep criticising and saying this is not the solution. But you don't provide any. – Jeremy Thille Oct 04 '17 at 13:42
  • @JeremyThille See what I wrote? You _should_ be able to interpret my very simple and basic suggestions. I provided all the details in my first reply - it is a complete description. – Mörre Oct 04 '17 at 13:42
  • Yes, I saw that you energetically said that this is not a solution, and pointed to some blog. In the meantime, @vanelizarov gave me something that works, therefore I'll do with that, thanks. – Jeremy Thille Oct 04 '17 at 13:44
  • @JeremyThille, `async` functions always return a promise. You don't have to explicitly create one. Whatever you return out of an `async` function will be the resolved value of the promise. – MinusFour Oct 04 '17 at 13:49
  • Wow, that's interesting. I do it because that's what I could find in the async/await tutorials, they promisify the awaited functions. I'll definitely try to remove the promises and simply return a value then, thanks :) – Jeremy Thille Oct 04 '17 at 13:52
1

Drop the new Promise around the await! You want only

async checkLink() {
    let resolvedValue
    for (let i = 0; i < 3; i++) {
        this.method = i
        resolvedValue = await this.tryToSolve()
        if (resolvedValue) break
    }
    console.log(`Method ${this.method} did the trick.`);
    return resolvedValue;
}

or much simpler

async checkLink() {
    for (let i = 0; i < 3; i++) {
        const value = await this.tryToSolve()
        if (value) {
            console.log(`Method ${i} did the trick.`);
            return value;
        }
    }
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375