Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.JS Airtable - Await doesn't wait for promise to be resolved

I am trying to get data from Airtable in my node.js app but I can't manage to get my results AFTER the resolution of my promise.

Here's my code:

async function getData(code) {
  return await airtableBase("Data")
    .select({
      filterByFormula: `{code} = "${code}"`,
    })
    .firstPage((err, records) => {
      if (err) {
        console.log(err);
        return {};
      }

      console.log(records[0].fields);
      return records[0].fields;
    });
}
stuff.map(async (object) => {
      embedData = getEmbedData(object);

      data = await getData(embedData.code);

      console.log(data);
})

Here's what I get logged:

undefined
undefined
undefined
{
  code: '1',
  fullname: 'Test 1',
  logo: '...'
}
{
  code: '2',
  fullname: 'Test 2',
  logo: '...'
}
{
  code: '3',
  fullname: 'Test 3',
  logo: '...'
}
like image 680
Raigato Avatar asked Oct 22 '25 09:10

Raigato


1 Answers

you assume that

airtableBase(...).select(...).firstPage((error, result) => {})

returns a Promise - it doesn't

rarely does a function that takes a node style callback ... i.e

function(error, result) 

return a Promise

Change getData to return a Promise

function getData(code) {
    return new Promise((resolve, reject) => {
        airtableBase("Data")
        .select({
            filterByFormula: `{code} = "${code}"`,
        })
        .firstPage((err, records) => {
            if (err) {
                console.log(err);
                return reject({});
            }
            console.log(records[0].fields);
            resolve(records[0].fields);
        });
    });
}

also, with

stuff.map(async (object) => {
      embedData = getEmbedData(object);

      data = await getData(embedData.code);

      console.log(data);
})

there's no guarantee the order will be correct, it probably will be in this case, but there's no guarantee

The above is better written

Promise.all(stuff.map((object) => {
    embedData = getEmbedData(object);
    return getData(embedData.code);
}))
.then(results => {
    results.forEach(item => console.log(item));
})

or if that code is in a async function

const results = await Promise.all(stuff.map((object) => {
    embedData = getEmbedData(object);
    return getData(embedData.code);
}))
results.forEach(item => console.log(item));

Note: absolutely no rejection testing done since your code doesn't, but really, you should try/catch (if using async/await) or .catch if using .then


Please note that .firstPage may actually return a Promise if no callback function is given, so your code may be simpler

function getData(code) {
    return airtableBase("Data")
    .select({
        filterByFormula: `{code} = "${code}"`,
    })
    .firstPage()
    .promise() /* this could be needed, again, depending on the library */
    .then(records => {
        return records[0].fields;
    });
}

However, as you have not indicated anything about the db library you are using, I can't be sure the above will work

like image 65
Bravo Avatar answered Oct 23 '25 22:10

Bravo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!