promise 標(biāo)準(zhǔn)在實(shí)現(xiàn) Promise 之前要清楚的是 JavaScript 中的 Promise 遵循了 Promises/A+ 規(guī)范,所以我們在編寫 Promise 時(shí)也應(yīng)當(dāng)遵循這個(gè)規(guī)范,建議認(rèn)真、仔細(xì)讀幾遍這個(gè)規(guī)范。最好是理解事件循環(huán),這樣對(duì)于理解js中的異步是怎么回事非常重要。 基本使用 Promise( (resolve, reject) {...} Promise((resolve, reject)=>'url'=>=>=>}).then(value =>((err)=>})promise 是處理異步結(jié)果的一個(gè)對(duì)象,承若狀態(tài)改變時(shí)調(diào)用對(duì)應(yīng)的回調(diào)函數(shù),resolve、reject用來改變promise 的狀態(tài),then 綁定成功、失敗的回調(diào)。 環(huán)境準(zhǔn)備安裝測試工具以及nodemon因?yàn)槲覀円趎ode環(huán)境調(diào)試自己寫的promise // nodemonnpm install nodemon -D// promise 測試工具npm install promises-aplus-tests -D 增加腳本命令"testPromise": "promises-aplus-tests myPromise/promise3.js", "dev": "nodemon ./myPromise/index.js -i " 各自的路徑改成自己的即可,這個(gè)在后面會(huì)用來測試。 基本架子根據(jù)規(guī)范實(shí)現(xiàn)一個(gè)簡單的promise,功能如下
= 'PENDING'= 'FULFILLED'= 'REJECTED'.status =.value =.reason =.onResolveCallbacks =.onRejectedCallbacks == (value) => (.status ===.status =.value = .onResolveCallbacks.forEach(fn =>= (reason) => (.status ===.status =.reason = .onRejectedCallbacks.forEach(fn => (.status = .onResolveCallbacks.push(() =>.onRejectedCallbacks.push(() => (.status === (.status ==== myPromise 訂閱傳進(jìn)來的fn是一個(gè)執(zhí)行器,接受resolve、reject參數(shù),通常我們在構(gòu)造函數(shù)中需要調(diào)用某個(gè)接口,這是一個(gè)異步的操作,執(zhí)行完構(gòu)造函數(shù)之后,在執(zhí)行then(),這個(gè)時(shí)候的狀態(tài)還是pending,所以我們需要把then 綁定的回調(diào)存起來,也可以理解為promise對(duì)象訂閱了這個(gè)回調(diào)。 發(fā)布在 resolve,reject函數(shù)中中我們改變了promise 對(duì)象的狀態(tài),既然狀態(tài)改變了,那么我們需要執(zhí)行之前訂閱的回調(diào),所以在不同的狀態(tài)下執(zhí)行對(duì)應(yīng)的回調(diào)即可。 流程
如上所示,實(shí)例化對(duì)象,執(zhí)行構(gòu)造函數(shù),碰到異步,掛起,然后執(zhí)行then()方法,綁定了resolve、reject的回調(diào)。如果異步有了結(jié)果執(zhí)行對(duì)應(yīng)的業(yè)務(wù)邏輯,調(diào)用resolve、或者reject,改變對(duì)應(yīng)的狀態(tài),觸發(fā)我們綁定的回調(diào)。 以上就是最基本的promise架子,但是還有promise 調(diào)用鏈沒有處理,下面繼續(xù)完善... 完善promise 調(diào)用鏈promose 的精妙的地方就是這個(gè)調(diào)用鏈,首先then 函數(shù)會(huì)返回一個(gè)新的promise 對(duì)象,并且每一個(gè)promise 對(duì)象又有一個(gè)then 函數(shù)。驚不驚喜原理就是那么簡單,回顧下then的一些特點(diǎn) then 特點(diǎn)
根據(jù)上面的特點(diǎn)以及閱讀規(guī)范我們知道then()函數(shù)主要需要處理以下幾點(diǎn)
返回一個(gè)新的promise因?yàn)閜romise 的鏈?zhǔn)秸{(diào)用涉及到狀態(tài),所以then 中返回的promise 是一個(gè)新的promise then(onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject) => { // do ... }) return promise2
}值的傳遞、狀態(tài)的改變let p = new myPromise((resolve, rejected) => { // do ...})
p.then(
value => { return 1
},
reason => {}
)
.then(
value => { return new Promise((resolve, rejected) => {
resolve('joel')
})
},
reason => {}
)
.then(
value => { throw 'err: 出錯(cuò)啦'
},
reason => {}
)then 返回的值可能是一個(gè)普通值、promise對(duì)象、function、error 等對(duì)于這部分規(guī)范文檔也有詳細(xì)的說明
[[Resolve]](promise, x)這個(gè)可以理解為promise 處理的過程,其中x是執(zhí)行回調(diào)的一個(gè)值,promise 是返回新的promise對(duì)象,完整代碼如下 我們將這部分邏輯抽成一個(gè)獨(dú)立的函數(shù) 如下 // 處理then返回結(jié)果的流程function resolvePromise(promise2, x, resolve, reject) { if (promise2 === x) { return reject(new TypeError('Chaining cycle detected for promise #<myPromise>'))
}
let called = false
if ((typeof x === 'object' && x !== null) || typeof x === 'function') { try {
let then = x.then // 判斷是否是promise
if (typeof then === 'function') {
then.call(x, (y) => { // 如果 resolvePromise 以值 y 為參數(shù)被調(diào)用,則運(yùn)行 [[Resolve]](promise, y)
if (called) return
called = true
resolvePromise(promise2, y, resolve, reject)
}, (r) => { if (called) return
called = true
reject(r)
})
} else {
resolve(x)
}
} catch (e) { if (called) return
called = true
reject(e)
}
} else { // 如果 x 不為對(duì)象或者函數(shù),以 x 普通值執(zhí)行回調(diào) resolve(x)
}
}測試promises-aplus-tests 這個(gè)工具我們必須實(shí)現(xiàn)一個(gè)靜態(tài)方法deferred,官方對(duì)這個(gè)方法的定義如下: deferred: 返回一個(gè)包含{ promise, resolve, reject }的對(duì)象 promise 是一個(gè)處于pending狀態(tài)的promise resolve(value) 用value解決上面那個(gè)promise reject(reason) 用reason拒絕上面那個(gè)promise 添加如下代碼 myPromise.defer = myPromise.deferred = function () {
let deferred = {}
deferred.promise = new myPromise((resolve, reject) => {
deferred.resolve = resolve
deferred.reject = reject
}) return deferred
}在編輯執(zhí)行我們前面加的命令即可 npm run testMyPromise
完善其他方法
npm run dev // 可以用來測試這些方法
源碼比較官方的源碼: https://github.com/then/promise 參考https://www.jianshu.com/p/4d266538f364 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all |
|
|