Promise/A+ 是 Promise 最小的一個規範,它包括:npm
1 promise狀態
2 then方法
3 promise解析過程
任何能跑通測試的 Promise 實現都被 Promise/A+ 承認。promise
1 咱們不知道異步請求何時返回數據,因此咱們就須要些回調函數。可是在某些狀況下咱們須要知道數據是在何時返回的,而後進行一些處理。
2 當咱們在異步回調裏面處理的操做仍是異步操做的時候,這樣就造成了異步回調的嵌套
那麼咱們就按照這個文檔來寫一個可經過測試的promise吧(https://www.ituring.com.cn/ar... 寫以前最好讀幾遍規範內容。話很少少,上代碼,爲了更好的展現我給代碼打了不少註釋,雖然很亂可是挺清楚的異步
//規範三種狀態,默認是pending;定義宏變量是爲了書寫時方便一點 const PENDING = 'pending'; const FULFILLED = 'fulfilled'; const REJECTED = 'rejected'; function resolvePromise(promise2, x, resolve, reject) { `若是promise和x指向同一對象,以TypeError爲據因拒絕執行promise` if (promise2 === x) { reject(new TypeError('Chaining cycle detected for promise #<Promise>--')) } let called; `判斷若是是對象或者函數` if ((typeof x === 'object' && x != null) || typeof x === 'function') { try { `文檔規定` let then = x.then; if (typeof then === 'function') { `若是then是函數,將x做爲函數的做用域this調用之,傳遞兩個回調函數做爲參數` then.call(x, y => { `防止重複調用` if (called) return; called = true; `若是是嵌套的promise那麼須要遞歸遍歷到普通值爲止` resolvePromise(promise2, y, resolve, reject) }, r => { `防止重複調用` if (called) return; called = true; reject(r) }) } else { `若是then不是函數,以x爲參數執行promise` resolve(x) } } catch (e) { `防止重複調用` if (called) return; called = true; `若是取x.then的值時拋出錯誤e,則以e爲據因拒絕promise` reject(e) } } else { `若是是普通值` resolve(x) } } `建立一個promise類` class Promise { constructor(executor) { this.status = PENDING; this.value = undefined; this.reason = undefined; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; `定義executor(resolve, reject)中的resolve,參數value` let resolve = value => { `只有狀態爲pending的狀況下才能轉換狀態` if (this.status === PENDING) { `調用reslove函數 狀態變爲成功態` this.status = FULFILLED; `定義變量接受傳進來的參數` this.value = value; `遍歷成功事件池中的方法並依次執行(解決異步)` this.onFulfilledCallbacks.forEach(fn => fn()) } }; `定義executor(resolve, reject)中的reject,參數reason` let reject = reason => { `只有狀態爲pending的狀況下才能轉換狀態` if (this.status === PENDING) { `調用reject函數 狀態變爲失敗態` this.status = REJECTED; `定義變量接受傳進來的參數` this.reason = reason; `遍歷失敗事件池中的方法並依次執行(解決異步)` this.onRejectedCallbacks.forEach(fn => fn()) } }; try { `默認傳進一個函數executor,而且執行,promise中的提供兩個函數` executor(resolve, reject) } catch (e) { `若是拋錯調用reject(文檔寫的)` reject(e) } } then(onFulfilled, onRejected) { `(成功態)連續調用時若是函數沒有寫給他附一個默認值繼續向下傳遞` onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : d => d; `(失敗態)若是函數沒有寫,那就把錯誤拋出去` onRejected = typeof onRejected === 'function' ? onRejected : e => { throw e }; `規範上寫調用.then時必須返回promise` let promise2 = new Promise((resolve, reject) => { `若是狀態爲成功態` if (this.status === FULFILLED) { setTimeout(() => { try { `接受.then後面第一個函數的返回值,爲了判斷有沒有拋錯使用了try包裹` let x = onFulfilled(this.value); `判斷x是promise仍是普通值,從而進行不一樣的處理,當調用這個函數時獲取不到promise因此這裏使用了異步` resolvePromise(promise2, x, resolve, reject) } catch (e) { `若是拋錯以後調用reject方法以e做爲緣由` reject(e) } }, 0); } if (this.status === REJECTED) { setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0); } if (this.status === PENDING) { `若是是異步的話,使用發佈訂閱模式,將事件放到對應的事件池中` this.onFulfilledCallbacks.push(() => { setTimeout(() => { try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) }); this.onRejectedCallbacks.push(() => { setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) }) } }); return promise2;//返回一個promise } } //導出咱們本身寫的promise module.exports = Promise;
1.安裝測試腳本函數
npm i -g promises-aplus-tests
2.在咱們寫的promise中寫入代碼測試
//測試代碼 Promise.defer = Promise.deferred = function () { let dfd = {}; dfd.promise = new Promise((resolve, reject) => { dfd.resolve = resolve; dfd.reject = reject; }) return dfd }
3.在當前文件夾下執行this
promises-aplus-tests xxx.js(本身寫promise的文件)