0

Curious issue I'm having dealing with some callback functions. I need to make a series of API calls that all return promises then I'm trying to take that data and map it to an array that exists on the global scope followed by a function to export the new data as a pdf - my issue is that the then() block is firing before the other function finishes and far before the first API call finshes. `

 let fireWatson = async () => {
        let watsonClassifed = []
        let watsonCallIndex = 0;
        let returnedArr = []
        for (let i = 0; i < watsonData.length; i++) {
            let params = {
                classifierId: '***********',
                collection: watsonData[i]
            }
            naturalLanguageClassifier.classifyCollection(params,
                 function (err, response) {
                    if (err)
                        console.log('error:', err);
                    else
                        console.log("data returned")
                        console.log(response.result.collection)
                    watsonClassifed.push(response.result.collection);
                    console.log(watsonClassifed)
                })

    } 
} 

fireWatson(watsonData).then(res =>
        console.log("firing stupid callbback after data")
    )

I realize this function isnt actually returning anything but is it possible to still make use of a promise without a return value or is this the main issue im hitting? Ideally - i want the then function to wait until the data is back - mapped to the global array and then outputted but this of course depends on proper synchronicity.

output:

[Done] exited with code=0 in 1.526 seconds

[Running] node "index.js"
firing stupid callbback 
data returned
all my sweet sweet data
Timotronadon
  • 315
  • 1
  • 2
  • 15
  • Your main issue is that you are not waiting for `naturalLanguageClassifier.classifyCollection` to finish, which you'll need to [promisify](https://stackoverflow.com/q/22519784/1048572) first before you can use `await` – Bergi May 30 '20 at 20:28

2 Answers2

1

All functions in JavaScript have returns, it's just that they are implicit if you don't say return explicitly

It's always a bit tricky to mix promises with callbacks. Here is a way you can fireWatson without using any utilities.

let fireWatson = async watsonData => Promise.all(watsonData.map(collection => new Promise((resolve, reject) => {
  let params = {
    classifierId: '***********',
    collection: collection,
  }
  return naturalLanguageClassifier.classifyCollection(params, function(err, response) => {
    if (err) {
      reject(err)
    } else {
      resolve(response)
    }
  })
})))

Of course, you can simplify this tremendously using a utility I created

const { map } = require('rubico')

let fireWatson = map(collection => new Promise((resolve, reject) => {
  let params = {
    classifierId: '***********',
    collection: watsonData[i]
  }
  return naturalLanguageClassifier.classifyCollection(params, function(err, response) => {
    if (err) {
      reject(err)
    } else {
      resolve(response)
    }
  })
}))
richytong
  • 2,387
  • 1
  • 10
  • 21
  • just for my clarification the then() block fires because nothnig was returned right? – Timotronadon May 30 '20 at 19:43
  • it's not quite right to say that nothing was returned; rather `Promise` was returned in the example you posted. `Promise` because the function used the `async` keyword. The Promise would contain the desired array if you return the promises like in the example in my answer. I will update my answer to reflect this better – richytong May 30 '20 at 20:08
  • gotcha! sitll unclear as to why the callback fires so quickly - does the undefined promise get returned right away? – Timotronadon May 30 '20 at 22:09
  • ah, so the callback fires so quickly because if you do not return the Promise.all(watsonData.map(...)) it will not wait for all those promises to resolve. – richytong May 30 '20 at 22:13
  • pleasure is all mine – richytong May 30 '20 at 22:14
0

turns out console.log was firing because every .then() block expects a function.

wrong:

 fireWatson(watsonData).then(res =>
            console.log("firing stupid callbback after data")
        ) 

right:

fireWatson(watsonData).then(()res =>
            console.log("firing stupid callbback after data")
        ) 
Timotronadon
  • 315
  • 1
  • 2
  • 15