In this blog post, I will share a technique for converting code that uses callbacks into code that utilizes async/await. I will provide an example and explain the steps involved in this transformation.
Let’s start with the original code that uses a callback:
const uploadFile = (callback) => {
// Upload the file, then call the callback with the location of the file
callback(location);
}
uploadFile((location) => {
// Continue with the logic
});
To convert this code to use async/await, we can wrap the body of the uploadFile
function in a return new Promise()
call. Once we have the desired data to return, we can use resolve()
to indicate a successful completion:
const uploadFile = () => {
return new Promise((resolve, reject) => {
// Upload the file, then call the callback with the location of the file
resolve(location);
});
}
const location = await uploadFile();
By using this approach, we can access the location
data directly in the first-level code, instead of having it wrapped within a callback function. This improves code cleanliness and makes it easier to reason about.
To illustrate this concept in a larger example, here’s the full code of an actual function:
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
}
});
});
And here’s how we can convert it using 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`);
});
By converting the code that uses a callback into code that takes advantage of the async/await pattern, we can improve code readability and maintainability. Now you can integrate this technique into your own projects.
Tags: callback, async/await, JavaScript, technical, code transformation