本文参考了Node.js 实践教程 - Promise 实现这个视频,并添加了本身的一些想法。javascript
首先来看 Promise 的构造:html
// 这里用 Prometheus 代替 Promise let p = new Prometheus((resolve, reject) => { resolve('hello') })
下面咱们来实现它:java
// 三种状态 const PENDING = Symbol() const FULFILLED = Symbol() const REJECTED = Symbol() function Prometheus (fn) { // fn 必须是函数 if (typeof fn !== 'function') { throw new Error('fn must be a function!') } let state = PENDING // 初始状态是 PENDING let value = null // 返回值 function fulfill (result) { state = FULFILLED value = result } // 完成时调用的方法,这里作了容错 function resolve (result) { try { fulfill(result) } catch (err) { reject(err) } } // 拒绝时调用的方法 function reject (error) { state = REJECTED value = error } fn(resolve, reject) }
第二步,实现 then 方法:promise
let p = new Prometheus((resolve, reject) => { resolve('hello') }) p.then(val => { console.log(val) })
// 三种状态 const PENDING = Symbol() const FULFILLED = Symbol() const REJECTED = Symbol() function Prometheus (fn) { // fn 必须是函数 if (typeof fn !== 'function') { throw new Error('fn must be a function!') } let state = PENDING // 初始状态是 PENDING let value = null // 返回值 function fulfill (result) { state = FULFILLED value = result } // 完成时调用的方法,这里作了容错 function resolve (result) { try { fulfill(result) } catch (err) { reject(err) } } // 拒绝时调用的方法 function reject (error) { state = REJECTED value = error } this.then = function (onFulfill, onReject) { switch (state) { case FULFILLED: onFulfill(value) break case REJECTED: onReject(value) break } } fn(resolve, reject) }
第三步,在 Promise 里使用异步bash
let p = new Prometheus((resolve, reject) => { setTimeout(() => { resolve('hello') }, 0) }) p.then(val => { console.log(val) })
直接运行上面的代码发现控制台没有打印出 hello
,缘由是 Prometheus
里的代码是异步执行,致使记下来执行 then
方法的时候,state
是 PENDING
,后面再执行 resolve
的时候就不会走到 onFulfill
了,因此咱们要在 then
方法里添加 state
为 PENDING
的分支判断,把 onFulfill
和 onReject
存到一个变量中:异步
// 三种状态 const PENDING = Symbol() const FULFILLED = Symbol() const REJECTED = Symbol() function Prometheus (fn) { // fn 必须是函数 if (typeof fn !== 'function') { throw new Error('fn must be a function!') } let state = PENDING // 初始状态是 PENDING let value = null // 返回值 let hanler = {} function fulfill (result) { state = FULFILLED value = result handler.onFulfill(result) } // 完成时调用的方法,这里作了容错 function resolve (result) { try { fulfill(result) } catch (err) { reject(err) } } // 拒绝时调用的方法 function reject (error) { state = REJECTED value = error handler.onReject(error) } this.then = function (onFulfill, onReject) { switch (state) { case FULFILLED: onFulfill(value) break case REJECTED: onReject(value) break case PENDING: handler = { onFulfill, onReject } } } fn(resolve, reject) }
异步实现了,咱们再回过头看看同步是否正常运行:函数
let p = new Prometheus((resolve, reject) => { resolve('hello') }) p.then(val => { console.log(val) })
发现报错信息:this
TypeError: handler.onReject is not a function
由于同步执行的时候,fulfill
里 handler
是 {}
,因此会报错。code
// 三种状态 const PENDING = Symbol() const FULFILLED = Symbol() const REJECTED = Symbol() function Prometheus (fn) { // fn 必须是函数 if (typeof fn !== 'function') { throw new Error('fn must be a function!') } let state = PENDING // 初始状态是 PENDING let value = null // 返回值 let handler = {} function fulfill (result) { state = FULFILLED value = result next(handler) } // 完成时调用的方法,这里作了容错 function resolve (result) { try { fulfill(result) } catch (err) { reject(err) } } // 拒绝时调用的方法 function reject (error) { state = REJECTED value = error next(handler) } function next({ onFulfill, onReject }) { switch (state) { case FULFILLED: onFulfill && onFulfill(value) break case REJECTED: onReject && onReject(value) break case PENDING: handler = { onFulfill, onReject } } } this.then = function (onFulfill, onReject) { next({onFulfill, onReject}) } fn(resolve, reject) }
如今同步也能够正常运行了,接下来看看多个 then
链式调用:视频
let p = new Prometheus((resolve, reject) => { resolve('hello') }) p.then(val => { console.log(val) return 'world' }).then(val => { console.log(val) })
执行代码会发现以下报错信息:
TypeError: Cannot read property 'then' of undefined
缘由是 then
方法没有返回 Promise
。
// 三种状态 const PENDING = Symbol() const FULFILLED = Symbol() const REJECTED = Symbol() function Prometheus (fn) { // fn 必须是函数 if (typeof fn !== 'function') { throw new Error('fn must be a function!') } let state = PENDING // 初始状态是 PENDING let value = null // 返回值 let handler = {} function fulfill (result) { state = FULFILLED value = result next(handler) } // 完成时调用的方法,这里作了容错 function resolve (result) { try { fulfill(result) } catch (err) { reject(err) } } // 拒绝时调用的方法 function reject (error) { state = REJECTED value = error next(handler) } function next({ onFulfill, onReject }) { switch (state) { case FULFILLED: onFulfill && onFulfill(value) break case REJECTED: onReject && onReject(value) break case PENDING: handler = { onFulfill, onReject } } } this.then = function (onFulfill, onReject) { return new Prometheus((resolve, reject) => { next({ onFulfill: val => { resolve(onFulfill(val)) }, onReject: err => { reject(onReject(err)) } }) }) } fn(resolve, reject) }
再次运行,正确打印出结果。
到此,一个很是简单的 Promise 就实现了,固然,这里其实还有不少细节没有考虑,具体还要参考 Promise/A+。