promise 標(biāo)準(zhǔn)在實(shí)現(xiàn) Promise 之前要清楚的是 JavaScript 中的 Promise 遵循了 Promises/A+ 規(guī)范,所以我們在編寫 Promise 時也應(yīng)當(dāng)遵循這個規(guī)范,建議認(rèn)真、仔細(xì)讀幾遍這個規(guī)范。最好是理解事件循環(huán),這樣對于理解js中的異步是怎么回事非常重要。 基本使用Promise( (resolve, reject) {...} Promise((resolve, reject)=>'url'=>=>=>}).then(value =>((err)=>}) promise 是處理異步結(jié)果的一個對象,承若狀態(tài)改變時調(diào)用對應(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 " 各自的路徑改成自己的即可,這個在后面會用來測試。 基本架子根據(jù)規(guī)范實(shí)現(xiàn)一個簡單的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是一個執(zhí)行器,接受resolve、reject參數(shù),通常我們在構(gòu)造函數(shù)中需要調(diào)用某個接口,這是一個異步的操作,執(zhí)行完構(gòu)造函數(shù)之后,在執(zhí)行then(),這個時候的狀態(tài)還是pending,所以我們需要把then 綁定的回調(diào)存起來,也可以理解為promise對象訂閱了這個回調(diào)。 發(fā)布在 resolve,reject函數(shù)中中我們改變了promise 對象的狀態(tài),既然狀態(tài)改變了,那么我們需要執(zhí)行之前訂閱的回調(diào),所以在不同的狀態(tài)下執(zhí)行對應(yīng)的回調(diào)即可。 流程如上所示,實(shí)例化對象,執(zhí)行構(gòu)造函數(shù),碰到異步,掛起,然后執(zhí)行then()方法,綁定了resolve、reject的回調(diào)。如果異步有了結(jié)果執(zhí)行對應(yīng)的業(yè)務(wù)邏輯,調(diào)用resolve、或者reject,改變對應(yīng)的狀態(tài),觸發(fā)我們綁定的回調(diào)。 以上就是最基本的promise架子,但是還有promise 調(diào)用鏈沒有處理,下面繼續(xù)完善... 完善promise 調(diào)用鏈promose 的精妙的地方就是這個調(diào)用鏈,首先then 函數(shù)會返回一個新的promise 對象,并且每一個promise 對象又有一個then 函數(shù)。驚不驚喜原理就是那么簡單,回顧下then的一些特點(diǎn) then 特點(diǎn)
根據(jù)上面的特點(diǎn)以及閱讀規(guī)范我們知道then()函數(shù)主要需要處理以下幾點(diǎn)
返回一個新的promise因?yàn)閜romise 的鏈?zhǔn)秸{(diào)用涉及到狀態(tài),所以then 中返回的promise 是一個新的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: 出錯啦' }, reason => {} ) then 返回的值可能是一個普通值、promise對象、function、error 等對于這部分規(guī)范文檔也有詳細(xì)的說明 [[Resolve]](promise, x)這個可以理解為promise 處理的過程,其中x是執(zhí)行回調(diào)的一個值,promise 是返回新的promise對象,完整代碼如下 我們將這部分邏輯抽成一個獨(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 不為對象或者函數(shù),以 x 普通值執(zhí)行回調(diào) resolve(x) } } 測試promises-aplus-tests 這個工具我們必須實(shí)現(xiàn)一個靜態(tài)方法deferred,官方對這個方法的定義如下: deferred: 返回一個包含{ promise, resolve, reject }的對象 promise 是一個處于pending狀態(tài)的promise resolve(value) 用value解決上面那個promise reject(reason) 用reason拒絕上面那個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 |
|