本文參考了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+。