這篇文章系列是由我上培訓班課程的一個筆記整理後完成。promise
帶小白一步步完成一個A+規範Promise實現,由淺入深。markdown
內容解析很是詳細,儘可能把每一個點爲何這樣寫都註釋清楚,某些地方甚至略顯囉嗦了。異步
平均一行代碼一句註釋,拆分爲三個版本1.0,2.0,3.0,層層遞進,最終3.0版本將實現Pomise/A+規範。(1.0版本保證簡單易懂)函數
至於本文爲何分爲上中下三篇,是怕不少人和我同樣看見太長的文章先收藏,再吃灰。ui
因此,毫不是懶:)。(其實就是)this
熟悉promise的讀者能夠直接看下一節源碼spa
myPromise 1.0
版本將完成一個能處理同步狀態的promise
(不考慮異步)。實現了promise
的如下特性,不少平常使用的時候並無注意到,殊不知不覺在用了。code
1.promise
構造函數接收一個executor
函數,且該函數當即執行(即同步執行)同步
2.executor
函數接收兩個promise
內部提供的方法resolve方法
和reject方法
用於供使用者調用,在合適的時候改變promise
成合適的狀態源碼
let mypromise = new Promise((resolve,reject) => {
//這個箭頭函數就是executor
})
複製代碼
3.executor
函數內部執行異常時會被捕獲並執行reject
let mypromise = new Promise((resolve,reject) => {
throw new Error('拋出異常')
//至關於執行了reject,代碼出現錯誤同理,會被捕獲且將錯誤傳給reject並執行。
})
複製代碼
4.具有三個狀態(resolve
成功,reject
失敗,pending
等待)和then方法(使用者用於傳入onFulfilled函數
和onRejected函數
)
let mypromise = new Promise((resolve,reject) => {
resolve('成功')
})
mypromise.then((data) => { //onFulfilled函數
console.log('then resolve---',data);
},(err) => { //onRejected函數
console.log('then reject---',err);
})
//注意:then中的使用者傳入的onFulfilled函數和使用者executor中使用的resolve都是成功時要調用的方法,能夠認爲resolve觸發onFulfilled。
//reject和onRejected同上
複製代碼
5.只有promise
處於pending
狀態時,內部的executor
才能成功調用resolve
或reject
並改變狀態。
let mypromise = new Promise((resolve,reject) => {
resolve('成功')//resolve內部會改變狀態由pending變resolve
resolve('成功2')//這三行執行已經沒有反應
reject('失敗')
throw new Error('拋出異常')
})
複製代碼
知道特性以後就是開始實現了,不得不感嘆大佬們的智慧。
很少說,開始上代碼,話都在註釋裏。
// myPromise 1.0
const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
const PENDING = 'PENDING'
console.log('my promise working');
class Promise {
constructor(executor) {//new Promise時,當即調用構造函數constructor,接收用戶傳入的executor。
this.status = PENDING;//默認等待態
this.value = undefined;//用於成功時數據存儲,多是js值,undefined,promise三者之一
this.reason = undefined;//用於失敗緣由儲存
let resolve = (value) => {//這兩個函數不綁定到this上是由於,這兩個函數不屬於實例,由使用者傳入
if(this.status === PENDING) {//只有等待態才能改變狀態並執行resolve函數,非等待態調用直接return
this.status = RESOLVED//用戶調用resolve時第一步,狀態置爲'resolve'
this.value = value//第二步,保存成功消息
}
}
let reject = (reason) => {//同上
if(this.status === PENDING) {//狀態已是resove或reject的時候即便調用也不執行
this.status = REJECTED
this.reason = reason
}
}
try {//在executor外包裹trycatch是爲了捕獲運行時的錯誤,以及throw new Error()這種非用戶主動調用reject時的狀況。
executor(resolve,reject);//執行器就是executor用戶傳入的函數,該函數當即執行
//並傳入兩個函數給執行器使用。
//並約定,用戶認爲成功或者說想調用'成功'方法或者是想將狀態置爲成功時使用resolve,並傳入成功消息
//反之調用reject,並傳入失敗緣由
} catch (error) {//假設trycatch捕獲到錯誤,自動調用reject。
reject(error)//也就是說,用戶主動調用reject和promise內executor運行出錯都會調用reject。
}
}
//上面是promise調用時初始化執行的構造器,下面是promise這個類自帶的方法
then(onFulfilled,onRejected) { //使用者調用promise的then方法,傳入成功時調用的函數,失敗時調用的函數
if(this.status === RESOLVED) {//而後then執行,根據promise的狀態決定調用的函數
onFulfilled(this.value);
}
if(this.status === REJECTED) {
onRejected(this.reason)
}
}
}
module.exports = Promise
//也就是說,用戶調用promise,promise當即執行,並改變promise的狀態,當用戶調用then的時候
//傳入兩個狀態對應的要執行的方法。promise根據當前狀態的不一樣,選擇執行resolve或reject
複製代碼
let Promise = require('./promise') //引入本身的promise實驗一下
let mypromise = new Promise((resolve,reject) => {
resolve('成功')//改變狀態由pending變resolve
throw new Error('拋出異常')//後兩行執行已經沒有反應
reject('失敗')
})
mypromise.then((data) => {
console.log('then resolve---',data);
},(err) => {
console.log('then reject---',err);
})
複製代碼
最後輸出:my promise working then resolve--- 成功
若是能幫到你們就是對我最大的鼓勵,1.5和2.0代碼註釋版已經基本完成,寫好後會排markdown版發出。
下期,1.5版本做爲過渡,2.0版本將解決異步、鏈式調用的問題。
myPromise1.0其實很簡單的東西,可是也不排除有沒發現的錯誤,你們輕噴,感謝閱讀,感謝指錯。