Instead of placing callbacks in your callbacks to be able callback whilst you callback, Promises allow us to write the code that resembles sync one (at least in vertical manner, contrary to the one pictured above, the callback hell):
Promise.resolve(5)
.then(x => x + 1)
.then(console.log)
.catch(console.error);
How to get a Promise?
First way is using the new Promise()
constructor. The async action (involving a callback) is run inside the constructor. The reslove()
and reject()
hooks are called inside the callback:
const promise = new Promise((resolve, reject) => {
// callback obeys NodeJS convention
asyncAction((err, result) => {
if (err) reject(err)
else resolve(result)
})
})
promise
.then(console.info)
.catch(console.error)
Second way uses a couple of static methods:
const resolved = Promise.resolve(5);
const rejected = Promise.reject("ERR_REJECTED");
resolved
.then(console.info)
.catch(console.error); // prints "5" as info message
rejected
.then(console.info)
.catch(console.error); // prints "ERR_REJECTED" as error message
Third way is an evolved first one and can be used only if a callback respects the NodeJS callback style (1st argument is an error object or null
if succeeded, 2nd argument delivers the result if any):
/**
* @param {Function} asyncHandler (...arguments, callback(err, results))
*/
function promisify(asyncHandler) {
return (...args) => new Promise((resolve, reject) => {
asyncHandler.call(
null,
(err, res) => {
if (err) reject(err)
else resolve(res)
},
...args
)
})
}
const readFile = require("fs").readFile
const promiseReadFile = promisify(readfile)
promiseReadFile("./example.txt")
.then(console.info)
.catch(console.error)
Lucky us programming nowadays: the promisify()
is included to NodeJS utils
since ages v8.0. If you're curious what's under the hood, check this out.
Mind also that NodeJS modules provide callback methods alongside with promisified ones:
import * as fsCb from "node:fs"
import * as fsProm from "node:fs/promises"
fsCb.stat("file.txt", (err, stat) => {
if (err) console.error("Error", err)
else console.info(stat)
})
// ——— vs ———
fsProm.stat("file.txt")
.then(stat => console.info(stat))
.catch(e => console.error("Error", e))
Wait, still Promises in 2024?
If you think that traditional Promise
is obsolete in the async/await
world, then hold on. Every async
function returns Promise
do its result can be treated as one:
async function delayed() {
// do some await
return 42
}
delayed()
.then(res => console.info(res))
.catch(e => console.error(e))
Next time we continue with chaining promises and building the data flow that resembles one from real world.