網上已經有不少前輩寫過該如何一步步的實現一個符合Promise/A+規範的文章了javascript
可是呢java
無論看多少篇、多少遍,真的不如本身對照規範一行一行手動敲一遍來的實在~ 😂😂😂es6
建議是多看幾遍規範,認真理解以後再開始一個功能一個功能的實現~npm
封面來源——ivanjov.com數組
阮一峯老師的文章 Promise對象promise
/** * 根據Promise/A+規範,實現本身的Promise * * Promise 表示一個異步操做的最終結果,與之進行交互的方式主要是 then 方法, * 該方法註冊了兩個回調函數,用於接收 promise 的終值或本 promise 不能執行的緣由。 * * 一個 Promise 的當前狀態必須爲如下三種狀態中的一種:等待態(Pending)、執行態(Fulfilled)和拒絕態(Rejected) * 而且只能由Pending -> Fulfilled 或者 Pending -> Rejected,且必須擁有一個不可變的終值或拒因 * * 一個 promise 必須提供一個 then 方法以訪問其當前值、終值和據因。 */
const PENDING = 'pending'
const FULFILLED = 'fulFilled'
const REJECTED = 'rejected'
function Promise (excutor) {
const that = this
that.status = PENDING
that.value = undefined
that.reason = undefined
// 存儲fulFilled狀態對應的onFulfilled函數
that.onFulfilledCallbacks = []
// 存儲rejected狀態對應的onRejected函數
that.onRejectedCallbacks = []
/** * @param {*} value 成功態接收的終值 * * 爲何resolve 加setTimeout? * 一 2.2.4規範 要確保 onFulfilled 和 onRejected 方法異步執行 * (且應該在 then 方法被調用的那一輪事件循環以後的新執行棧中執行) 因此要在resolve里加上setTimeout * * 二 2.2.6規範 對於一個promise,它的then方法能夠調用屢次.(當在其餘程序中屢次調用同一個promise的then時 * 因爲以前狀態已經爲FULFILLED/REJECTED狀態,則會走的下面邏輯),因此要確保爲FULFILLED/REJECTED狀態後 也要異步執行onFulfilled/onRejected * * onFulfilled 和 onRejected 必須被做爲函數調用(即沒有 this 值),且只容許在執行環境堆棧僅包含平臺代碼時運行 * 對應規範中 2.2.4 * * 這裏的平臺代碼指的是引擎、環境以及 promise 的實施代碼。實踐中要確保 onFulfilled * 和 onRejected 方法異步執行,且應該在 then 方法被調用的那一輪事件循環以後的新執行棧中執行。 */
function resolve (value) {
// 解決resolve方法嵌套返回promise的問題
if (value instanceof Promise) {
return value.then(resolve, reject)
}
setTimeout(() => {
if (that.status === PENDING) {
// 只能由 pending -> fulfilled狀態 (避免調用屢次resolve reject)
that.status = FULFILLED
that.value = value
// 分別執行成功狀態訂閱器中的回調方法
that.onFulfilledCallbacks.forEach(cb => cb(that.value))
}
})
}
/** * 爲何reject中不用判斷reason類型? * @param {*} reason 失敗態接收到拒因 */
function reject (reason) {
setTimeout(() => {
if (that.status === PENDING) {
// 只能由 pending -> rejected狀態 (避免調用屢次resolve reject)
that.status = REJECTED
that.reason = reason
// 分別執行訂失敗狀態閱器中的回調方法
that.onRejectedCallbacks.forEach(cb => cb(that.reason))
}
})
}
// 捕獲excutor執行器中的異常
try{
excutor(resolve, reject)
} catch (err) {
reject(err)
}
}
/** * 註冊fulfilled狀態/rejected狀態的回調函數 * @param {Function} onFulfilled fulfilled狀態執行的函數 * @param {Function} onRejected rejected狀態執行的函數 * @returns {Function} newPromise 返回一個新的promised */
Promise.prototype.then = function (onFulfilled, onRejected) {
/** * 處理參數默認值,保證後續能夠繼續執行 * 對應規範中 2.2.1 若是 onFulfilled / onRejected 不是函數,其必須被忽略 * */
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason;
};
/** * then裏面的FULFILLED/REJECTED狀態時, 爲何要加setTimeout? * */
let that = this
let promise2
if (that.status === FULFILLED) {
return promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try{
let x = onFulfilled(that.value)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
})
})
}
if (that.status === REJECTED) {
return promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try{
let x = onRejected(that.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
})
})
}
if (that.status === PENDING) {
// 這裏是爲了解決異步的問題,採用發佈訂閱的方式,下面兩個數組分別存儲成功和失敗的回調
// 返回一個Promise是爲了解決能夠鏈式調用的問題
return promise2 = new Promise((resolve, reject) => {
that.onFulfilledCallbacks.push((value) => {
try {
let x = onFulfilled(value)
// 解析promise流程
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
})
that.onRejectedCallbacks.push((reason) => {
try {
let x = onRejected(reason)
// 解析promise流程
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
})
})
}
}
function resolvePromise (promise2, x, resolve, reject) {
// console.log(this)
// 若是 promise 和 x 指向同一對象,會致使循環引用報錯,So 以 TypeError 爲據因拒絕執行 promise
// 對應規範中 2.3.1
if (promise2 === x) {
return reject(new TypeError('循環引用'))
}
// promise2是否已經resolve或者reject,避免重複調用
let called = false
// 若是x是一個promise對象,繼續resolve
// 對應規範中 2.3.2
if (x instanceof Promise) {
// 若是是等待狀態,則須要保持等待態直至 x 被執行 / 被拒絕,並解析y值
// 對應規範中 2.3.2.1
if (x.status === PENDING) {
x.then(y => {
resolvePromise(promise2, y, resolve, reject)
}, reason => {
reject(reason)
})
} else {
// 若是x已經處於執行態 / 拒絕態,則用相同的值 / 拒因 執行promise
// 對應規範中 2.3.2.2 和 2.3.2.3
x.then(resolve, reject)
}
// 若是 x 爲對象或者函數
// 對應規範中 2.3.3
} else if (x !== null && ((typeof x === 'object') || (typeof x === 'function'))) {
try {
/** * 這步咱們先是存儲了一個指向 x.then 的引用,而後測試並調用該引用,以免屢次訪問 x.then 屬性。 * 這種預防措施確保了該屬性的一致性,由於其值可能在檢索調用時被改變。 * 對應規範中 2.3.3.1 */
let then = x.then
/** * 若是 then 是函數,將 x 做爲函數的做用域 this 調用之。 * 傳遞兩個回調函數做爲參數,第一個參數叫作 resolvePromise ,第二個參數叫作 rejectPromise * 對應規範中 2.3.3.3 */
if (typeof then === 'function') {
then.call(x, y => {
/** * 若是 resolvePromise 和 rejectPromise 均被調用, * 或者被同一參數調用了屢次,則優先採用首次調用並忽略剩下的調用 * 對應規範中 2.3.3.3.3 */
if (called) return
called = true
// 對應規範中 2.3.3.3.1
resolvePromise(promise2, y, resolve, reject)
}, reason => {
if (called) return
called = true
// 若是 rejectPromise 以據因 r 爲參數被調用,則以據因 r 拒絕 promise
// 對應規範中 2.3.3.3.2
reject(reason)
})
} else {
// 若是 then 不是函數,以 x 爲參數執行 promise
// 對應規範中 2.3.3.4
resolve(x)
}
} catch (e) {
// 若是調用 then 方法拋出了異常 e
// 對應規範中 2.3.3.3.4
// 若是 resolvePromise 或 rejectPromise 已經被調用,則忽略之
// 對應規範中 2.3.3.3.4.1
if (called) return
called = true
// 不然以 e 爲據因拒絕 promise
// 對應規範中 2.3.3.3.4.2
reject(e)
}
} else {
// 若是 then 不是函數,是一個普通的值,以 x 爲參數執行 promise
// 對應規範中 2.3.4
resolve(x)
}
}
複製代碼
// 在promise實現的代碼中,增長如下執行測試用例須要用到的代碼
Promise.deferred = function() {
let defer = {};
defer.promise = new Promise((resolve, reject) => {
defer.resolve = resolve;
defer.reject = reject;
});
return defer;
}
try {
module.exports = Promise
} catch (e) {
console.log(e, '---')
}
複製代碼
// 安裝測試腳本
npm i -g promises-aplus-tests
// 測試命令
promises-aplus-tests Promise.js
// 872 passing
複製代碼
// 馬上返回一個promise,通常用於沒有promise對象,須要將一個東西,轉爲promise
Promise.resolve = function (data) {
return new Promise(resolve => {
resolve(data)
})
}
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
// 接收一個promise數組,所有成功以後才往下執行,並返回一個promise
Promise.all = function (promiseArray) {
return new Promise((resolve, reject) => {
let resolveArr = []
promiseArray.forEach(item => {
item.then(data => {
resolveArr.push(data)
console.log(data, '---data')
if (promiseArray.length === resolveArr.length) {
resolve(resolveArr)
}
}, reason => {
reject(reason)
})
})
})
}
// 接收一個promise數組,只要有一個先返回,不管是resolve仍是reject,都會往下執行then中的成功或者失敗回調,
// 其餘的promise也會繼續執行,可是不會使用結果
Promise.race = function (promiseArray) {
return new Promise((resolve, reject) => {
promiseArray.forEach(item => {
item.then(data => {
resolve(data)
}, reason => {
reject(reason)
})
})
})
}
// 用於捕獲錯誤的回調,即第一個resolve參數爲null的特殊then方法
Promise.prototype.catch = function (reject) {
return this.then(null, reject)
}
// 不管前面執行結果狀態,都會進入該方法中,且會將值原封不動的傳給後面的then
Promise.prototype.finally = function (callback) {
return this.then(value => {
return new Promise(callback()).then(() => {
return value
})
}, reason => {
return new Promise(callback()).then(() => {
throw reason
})
})
}
複製代碼