I’m pretty new to NodeJS and trying to learn better ways to handle async operations. I’m working with Airtable’s API to fetch records from a database table and store them for later use in JSON or CSV format.
Right now I’m using callbacks but the code is getting messy. I’ve heard about Promises and async/await but I’m not sure how to implement them properly.
Here’s what I have so far:
const Airtable = require('airtable');
Airtable.configure({
endpointUrl: 'https://api.airtable.com',
apiKey: 'your-api-key-here'
});
const database = Airtable.base('your-base-id');
const viewName = "Grid view";
let dataArray = [];
database('Users').select({
view: viewName
}).eachPage(function processPage(records, getNextPage){
records.forEach(function(item){
dataArray.push({
"FullName": item.get('FullName'),
"Comments": item.get('Comments')
});
});
getNextPage();
saveData(dataArray);
}, function finished(err){
if(err){
console.log(err);
console.log(dataArray);
}
});
function saveData(array) {
convertToJson(array);
return array;
}
function convertToJson(array){
console.log(array);
return JSON.stringify(array);
}
What’s the best way to avoid callback hell here? Should I use Promises or is there a simpler approach for this use case?
Your problem is you’re calling saveData(dataArray) inside the eachPage callback - that runs after every single page, not at the end. Move it to the finished callback instead.
For better async handling, wrap the Airtable operation in a Promise and use async/await. Here’s how I’ve restructured similar code:
function fetchAirtableData() {
return new Promise((resolve, reject) => {
let dataArray = [];
database('Users').select({ view: viewName })
.eachPage(
function page(records, fetchNextPage) {
records.forEach(record => {
dataArray.push({
"FullName": record.get('FullName'),
"Comments": record.get('Comments')
});
});
fetchNextPage();
},
function done(err) {
if (err) reject(err);
else resolve(dataArray);
}
);
});
}
// Usage
async function main() {
try {
const data = await fetchAirtableData();
const jsonData = JSON.stringify(data);
console.log(jsonData);
} catch (error) {
console.error(error);
}
}
This kills the nested callback mess and makes error handling way cleaner.
just use async/await with try-catch - way cleaner than promises. your saveData function runs on every page, which isn’t what you want. move it to the finished callback and wrap everything in an async function. also, your convertToJson function just returns a string that goes nowhere - it’s not actually saving anything.
Had this exact same issue when I started with Airtable’s API last year. You’re mixing sync and async operations wrong - that’s what’s breaking everything. Don’t wrap everything in promises. Use util.promisify to convert Airtable’s callback methods instead. Way cleaner and you won’t have to rewrite everything: javascript const util = require('util'); async function getAllRecords() { const records = []; await database('Users').select({ view: viewName }) .eachPage(async (pageRecords, fetchNextPage) => { pageRecords.forEach(record => { records.push({ FullName: record.get('FullName'), Comments: record.get('Comments') }); }); fetchNextPage(); }); return records; } // Then use it getAllRecords() .then(data => { console.log(JSON.stringify(data)); // Save to file here }) .catch(console.error); This keeps Airtable’s pagination working while giving you proper async control. Way less buggy than building promises manually.
Promises work but you’re still wrestling with Airtable’s API manually. Been there - found something way better.
Skip the callbacks and promises entirely. Just automate it. I built workflows that extract, transform, and export Airtable data without all that boilerplate nonsense.
Workflow connects to Airtable, grabs records automatically, spits out whatever format you want (JSON, CSV, whatever), and schedules regular exports. No callback hell or promise chains.
I use this for tons of data ops at work. Handles pagination, rate limits, retries - all automatically. Way more reliable than custom code.
Trigger via webhook, schedule it, or chain with other operations like sending data elsewhere.
Check it out: https://latenode.com