Skip to content

Instantly share code, notes, and snippets.

@tannerwelsh
Created July 7, 2017 16:44
Show Gist options
  • Save tannerwelsh/5236252ffacfb0867e65269f4a4547b7 to your computer and use it in GitHub Desktop.
Save tannerwelsh/5236252ffacfb0867e65269f4a4547b7 to your computer and use it in GitHub Desktop.
Reverse-engineering Promise (loosely)
// This is a very bare-bones (and incomplete) implementation of the idea
// behind Promise, using a new function called Commitment:
const Commitment = function(func) {
this.state = 'PENDING' // will be changed to 'FULFILLED' or 'REJECTED'
const resolve = (result) => {
this.state = 'FULFILLED'
this.resolver && this.resolver(result)
}
const reject = (error) => {
this.state = 'REJECTED'
this.rejecter && this.rejecter(error)
}
func(resolve, reject)
}
Commitment.prototype.then = function(callback) {
this.resolver = callback
return this
}
Commitment.prototype.catch = function(callback) {
this.rejecter = callback
return this
}
// --- Example usage below ---
// This function will serve as our asynchronous code that the Commitment will wrap
// Uncomment the `throw Error('Oh no!')` to trigger the `catch` part of the Commitment
const asyncFunc = (resolve, reject) => {
setTimeout(() => {
try {
// code that could throw an error
// throw Error('Oh no!')
} catch (err) {
return reject(err)
}
return resolve('Success!')
}, 1000)
}
// Test out our Commitment with an asynchronous function!
const longFunc = new Commitment(asyncFunc)
// Set up some monitoring to show the change in state
const logState = () => console.log(`Current state of longFunc: ${longFunc.state}`)
const monitor = setInterval(logState, 200)
longFunc.then((result) => {
clearInterval(monitor)
logState()
console.log(result)
})
longFunc.catch((err) => {
clearInterval(monitor)
logState()
console.error(err)
})
// This is how the Promise feature works in normal JS
// This function will serve as our asynchronous code that the Promise will wrap
// Uncomment the `throw Error('Oh no!')` to trigger the `catch` part of the Promise
const asyncFunc = (resolve, reject) => {
setTimeout(() => {
try {
// code that could throw an error
// throw Error('Oh no!')
} catch (err) {
return reject(err)
}
return resolve('Success!')
}, 1000)
}
// Using a Promise object, we can attach handlers for success (with `then()`)
// and failure (with `catch()`)
const longFunc = new Promise(asyncFunc)
longFunc.then((result) => {
console.log(result)
})
longFunc.catch((err) => {
console.error(err)
})
@AndrewGibson27
Copy link

This is great. A couple weeks ago, I was trying to figure this out myself -- and was having trouble knowing where to start. Then, I found your code! I tried to add functionality for chaining .then() calls as well as doing synchronous actions. I'd be curious what you think:
https://codepen.io/andrewgibson/pen/rwQrpd

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment