Join the AI Workshop and learn to build real-world apps with AI. A hands-on, practical program to level up your skills.
If you have code that uses callbacks, you can convert it to use async/await for cleaner, more readable code.
Here’s a callback-based example:
const uploadFile = (callback) => {
//upload the file, then call the callback with the location of the file
callback(location)
}
uploadFile((location) => {
// go on
})
See? We call uploadFile and when it finishes doing what it needs to do, it calls the callback function.
To convert this to async/await, wrap the body of the function in a return new Promise() call, and when you get the data you want to return, call resolve():
const uploadFile = () => {
return new Promise((resolve, reject) => {
//upload the file, then call resolve with the location of the file
resolve(location)
})
}
const location = await uploadFile()
Now we can use the location data directly, instead of it being wrapped in the callback function.
It helps keep the code cleaner and reason about it more clearly.
Here’s a full example. The original callback-based code:
const uploadFile = (fileName, id, callback) => {
const fileContent = fs.readFileSync(fileName)
const params = {
Bucket: process.env.AWS_BUCKET_NAME,
Key: `file.jpg`,
Body: fileContent
}
s3.upload(params, (err, data) => {
if (err) {
throw err
}
callback(data.Location)
})
}
uploadFile(files.logo.path, job.id, async (location) => {
await prisma.job.update({
where: { id: job.id },
data: {
logo: location
}
})
})
Here’s what it looks like after converting to async/await:
const uploadFile = (fileName, id) => {
return new Promise((resolve, reject) => {
const fileContent = fs.readFileSync(fileName)
const params = {
Bucket: process.env.AWS_BUCKET_NAME,
Key: `job-${id}.jpg`,
Body: fileContent
}
s3.upload(params, (err, data) => {
if (err) {
reject(err)
}
resolve(data.Location)
})
})
}
handler.post(async (req, res) => {
const files = req.files
const body = req.body
const job = await prisma.job.create({
data: {
...body,
created_at: new Date().toISOString()
}
})
const location = await uploadFile(files.logo.path, job.id)
await prisma.job.update({
where: { id: job.id },
data: {
logo: location
}
})
res.redirect(`/jobs/${job.id}/payment`)
})
The code is now more linear and easier to follow. Note how we use reject() for errors and resolve() for successful completion.
Lessons in this unit:
| 0: | Introduction |
| 1: | Callbacks |
| 2: | Timers |
| 3: | Promises |
| 4: | Async functions |
| 5: | Chaining promises |
| 6: | Orchestrating promises |
| 7: | Top-level await |
| 8: | Async with array methods |
| 9: | ▶︎ Converting callbacks to async/await |