Promises use "continuation-passing style" ("CPS").
The node approach to CPS is that asynchronous functions accept callbacks. Like so:
const FS = require('fs')
FS.readFile( path, 'utf8', function callback(error, data) {
// FS.readFile will invoke this function with an error or the file contents
// once the read operation is complete
})
An explicit promise (i.e. not async
/await
), looks pretty similar:
const myPromise = new Promise(function callback(resolve, reject) {
// invoke the non-blocking thing, then use resolve or reject to pass something onward
} )
The callback function is a "continuation," and you provide that continuation to the
asynchronous function knowing that it will eventually be invoked with whatever is the result of the non-blocking task.
Promises often look similar, at least superficially. Promise polyfills (which are often not needed) literally work by using some hairy but non-magical CPS code, plus timeouts or events, to provide the same interface. I suspect that modern JS engines use some kind of lower-level mechanism that does not lean on CPS to wire the data into the "callback."