简体   繁体   中英

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: '...'
}

you assume that

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

returns a Promise - it doesn't

rarely does a function that takes a node style callback ... ie

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM