2

I have an async function that calls another async function using await but the first function does not wait for the second function to complete.

module.exports.checkNewUser = async(uuid) => {
    const getUserQuery = `MATCH (n:USER {uuid:"${uuid}"}) RETURN n;`
    console.log(getUserQuery)
    console.log('1')
    const result = await this.runCypherQuery(getUserQuery)
    console.log('3')
    console.log('results:')
    console.log(JSON.stringify(result, null, indent))
    if(result !== []) throw new Error('user already exists')
    return
}

const request = require('request')
const uri = 'http://localhost:7474/db/data/transaction/commit'

module.exports.runCypherQuery = async(query) => {
    const headers = { Authorization: 'Basic xxx' }
    const json = {statements: [{statement: query, parameters: {}}]}
    //console.log(json)
    request.post({uri: uri, headers: headers, json: json}, (err, res, body) => {
        if(err) throw new Error(err.message)
        //console.log(body)
        const data = body.results[0].data
        console.log('data:')
        console.log(data)
        console.log('2')
        return data
    })
}

The terminal output is:

MATCH (n:USER {uuid:"xxx"}) RETURN n;
1
3
results:
undefined
data:
[]
2
Mark Tyers
  • 2,282
  • 3
  • 20
  • 38
  • 1
    Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Luca Kiebel Aug 04 '18 at 10:14
  • The possible duplicate involves the use of JQuery and callbacks, I've already checked this post, cheers. – Mark Tyers Aug 04 '18 at 10:16
  • @MarkTyers the problem is still the same `$.ajax( { ..., success: function(response) {...})` is equivalent to your `request.post({...}, (err, res, body) => {...})` both use a callback to handle the async result. And the solution is to wrap that code into a new Promise to convert the old callback based handling of an async result, into a Promise based version. – t.niese Aug 04 '18 at 10:56
  • Unrelated to you question, but what do you expect that `result !== []` should do? This will always evaluate to `true`. – t.niese Aug 04 '18 at 10:59

2 Answers2

4

Your runCypherQuery is not returning anything special at the moment. In order to await it, you need to explicitly specify that it returns a Promise that resolves once the request completes. Just awaiting an async function doesn't mean that the async function waits for all asynchronous operations to complete before resolving. Convert the callback-based request to a Promise and return that Promise, so that it can be awaited properly:

module.exports.runCypherQuery = (query) => {
  const headers = { Authorization: 'Basic xxx' }
  const json = {statements: [{statement: query, parameters: {}}]}
  return new Promise((resolve, reject) => {
    request.post({uri: uri, headers: headers, json: json}, (err, res, body) => {
      if(err) reject(err.message)
      //console.log(body)
      const data = body.results[0].data
      console.log('data:')
      console.log(data)
      console.log('2')
      resolve(data)
    })
  })
}
CertainPerformance
  • 260,466
  • 31
  • 181
  • 209
  • async functions don't support the `resolve()` function. The return statement resolves the implicit promise. – Mark Tyers Aug 04 '18 at 10:19
  • 1
    @MarkTyers the `return data` is not in a `async` function but in the callback function of the `request.post(`. The `request.post` uses the _old_ callback style to handle the async response, and because of that you need to wrap it into an own Promise which indeed has a `resolve` parameter. Or you have use a promise based variant of `request` like [request-promise](https://github.com/request/request-promise) or [request-promise-native](https://github.com/request/request-promise-native) – t.niese Aug 04 '18 at 10:32
  • The equivalent of `if(err) throw new Error(err.message)` would be `if(err) reject(new Error(err.message))`. Personally I would re-throw the error using `if(err) reject(err)`, because it would have a better error stack trace, but that's up to the OP. – t.niese Aug 04 '18 at 10:42
  • Thanks for the advice which has helped me to solve the problem however I can't accept this solution because the code is the answer is invalid. – Mark Tyers Aug 05 '18 at 08:22
  • 1
    @MarkTyers Can you explain what exactly the problem is with the code in the answer? Thanks – CertainPerformance Aug 05 '18 at 08:24
  • Sorry, my bad. I added it to my code and forgot to update the headers. – Mark Tyers Aug 05 '18 at 08:26
0

For the sake of completeness and based on the advice given by @CertainPerformance, this version uses the request-promise package in an asynchronous function.

const rp = require('request-promise')
const uri = 'http://localhost:7474/db/data/transaction/commit'

module.exports.runQuery = async(query) => {
    const headers = { Authorization: 'Basic xxx' }
    const json = {statements: [{statement: query, parameters: {}}]}
    //console.log(json)
    const body = await rp.post({uri: uri, headers: headers, json: json})
    return body.results[0].data
}
Mark Tyers
  • 2,282
  • 3
  • 20
  • 38