I am learning about Javascript Promise
and async
/await
. The sample code below asynchronously reads and parses a JSON file in node.js (my node.js version is v10.0.0).
In the sample code, ChainReadJson function and AwaitReadJson function are doing the same thing, reading and parsing a JSON file. The difference is that ChainReadJson function uses a promise chain, while AwaitReadJson function uses async/await.
const FS = require("fs");
function ReadFile(fileName) {
return new Promise((Resolve, Reject) => {
FS.readFile(fileName, 'utf8', (error, result) => {
if (error)
Reject(error);
else
Resolve(result);
});
});
}
// function using promise chain
function ChainReadJson(fileName, CallBack) {
ReadFile(fileName)
.then(
res => JSON.parse(res),
err => {
Message(-1, err.message);
}
)
.then(
res => {
if (res !== undefined)
CallBack(fileName, res);
},
err => {
Message(-2, err.message);
}
);
}
// function using async/await
async function AwaitReadJson(fileName, CallBack) {
let res, json;
try {
res = await ReadFile(fileName);
}
catch (err) {
Message(-1, err.message);
return;
}
try {
json = JSON.parse(res);
}
catch (err) {
Message(-2, err.message);
return;
}
CallBack(fileName, json);
}
ChainReadJson('test.json', PrintJSON);
AwaitReadJson('test.json', PrintJSON);
// common functions
function PrintJSON(fileName, json) {
console.log(`JSON[${fileName}]:`, json);
}
function Message(n, str) {
console.log(`[${n}]`, str);
}
When writing the code for ChainReadJson function using promise chain, I had difficulties controlling execution results and errors. However, when writing the code for AwaitReadJson function using async/await, those difficulties are mostly disappeared.
Do I correctly understand the benefits of async/await? What are the disadvantages of async/await compared to promise chain?
(The sample code is a modified version of the code in this answer. The original code uses promise chain only, and is written to know exactly where in the chain the error occurred and what is the error)
Indeed, async/await
were designed to reduce boilerplate and make asynchronous programs easier to write, compared to callbacks, promises, and generator functions.
While async/await
can be a nice way to cleanup asynchronous logic, it's worth pointing out that the promise logic can be cleaned up significantly, to the point of being very similar to the async/await alternative:
const fs = require("fs");
const util = require("util")
//Could also use the experimental "fs/promise" api from node v10
const promisifiedReadFile = util.promisify(fs.readFile);
const readFile = (fileName) => promisifiedReadFile(fileName, 'utf8');
function chainReadJson(fileName, callback) {
return readFile(fileName)
.then(json => JSON.parse(json))
.then(result => callback(null, result))
.catch(e => {
console.log("Error reading or parsing file", e.message);
callback(e)
});
}
The only functional difference here is that all the error logging occurs at one place, at the end of the chain.
It's possible to preserve the split logging for the readFile and the JSON.parse, but that is admittedly a bit trickier. You generally want to re-throw errors after handling them, so that the downstream .then
handlers are skipped: but if you throw the error again, it'll be caught again by the downstream .catch
handlers, which will cause duplicate logging, if you don't find a way to filter it out.
It's doable, but it's a bit of a pain, so I left it out of the above code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With