JavaScript基礎(chǔ)教程之如何實現(xiàn)一個簡單的promise
前言
我們在開發(fā)過程中大多會用到promise,想必大家對promise的使用都很熟練了,今天我們就來實現(xiàn)一個簡單的promise,實現(xiàn)的效果如有出入還往指正。
Promise/A+規(guī)范:
- 首先重新閱讀了下A+的規(guī)范:
- promise代表了一個異步操作的最終結(jié)果,主要是通過then方法來注冊成功以及失敗的情況,
- Promise/A+歷史上說是實現(xiàn)了Promise/A的行為并且考慮了一些不足之處,他并不關(guān)心如何創(chuàng)建,完成,拒絕Promise,只考慮提供一個可協(xié)作的then方法。
術(shù)語:
- promise是一個擁有符合上面的特征的then方法的對象或者方法。
- thenable是定義了then方法的對象或者方法
- value是任何合法的js的值(包括undefined,thenable或者promise)
- exception是一個被throw申明拋出的值
- reason是一個指明了為什么promise被拒絕
整體結(jié)構(gòu)
我們先來梳理一下整體的結(jié)果,以便后續(xù)好操作
class MyPromise { constructor(fn){ } resolve(){ } then(){ } reject(){ } catch(){ } }
Promise理論知識
摘抄至 http://es6.ruanyifeng.com/#docs/promise#Promise-all
Promise對象有以下兩個特點。
(1)對象的狀態(tài)不受外界影響。Promise對象代表一個異步操作,有三種狀態(tài):pending(進行中)、fulfilled(已成功)和rejected(已失敗)。只有異步操作的結(jié)果,可以決定當前是哪一種狀態(tài),任何其他操作都無法改變這個狀態(tài)。這也是Promise這個名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變。
(2)一旦狀態(tài)改變,就不會再變,任何時候都可以得到這個結(jié)果。Promise對象的狀態(tài)改變,只有兩種可能:從pending變?yōu)閒ulfilled和從pending變?yōu)閞ejected。只要這兩種情況發(fā)生,狀態(tài)就凝固了,不會再變了,會一直保持這個結(jié)果,這時就稱為 resolved(已定型)。如果改變已經(jīng)發(fā)生了,你再對Promise對象添加回調(diào)函數(shù),也會立即得到這個結(jié)果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監(jiān)聽,是得不到結(jié)果的。
總結(jié)一下就是promise有三種狀態(tài):pending(進行中)、fulfilled(已成功)和rejected(已失?。?,還有就是狀態(tài)的改變只能是pending -> fulfilled 或者 pending -> rejected,這些很重要
實現(xiàn)構(gòu)造函數(shù)
現(xiàn)在我們開始實現(xiàn)構(gòu)造函數(shù)
class MyPromise { constructor(fn){ if(typeof fn !== 'function') { throw new TypeError(`MyPromise fn ${fn} is not a function`) } this.state = 'pending'; this.value = void 0; fn(this.resolve.bind(this),this.reject.bind(this)) } ... }
構(gòu)造函數(shù)接收一個參數(shù)fn,且這個參數(shù)必須是一個函數(shù),因為我們一般這樣使用new Promise((resolve,reject)=>{});
然后初始化一下promise的狀態(tài),默認開始為pending,初始化value的值。
fn接收兩個參數(shù),resolve、reject
resolve
class MyPromise { constructor(fn){ if(typeof fn !== 'function') { throw new TypeError(`MyPromise fn ${fn} is not a function`) } this.state = 'pending'; this.value = void 0; fn(this.resolve.bind(this),this.reject.bind(this)) } resolve(value){ if(this.state !== 'pending') return; this.state = 'fulfilled'; this.value = value } ... }
當resolve執(zhí)行,接收到一個值之后;狀態(tài)就由 pending -> fulfilled;當前的值為接收的值
reject
class MyPromise { constructor(fn){ if(typeof fn !== 'function') { throw new TypeError(`MyPromise fn ${fn} is not a function`) } this.state = 'pending'; this.value = void 0; fn(this.resolve.bind(this),this.reject.bind(this)) } resolve(value){ if(this.state !== 'pending') return; this.state = 'fulfilled'; this.value = value } reject(reason){ if(this.state !== 'pending') return; this.state = 'rejected'; this.value = reason } }
當reject執(zhí)行,接收到一個值之后;狀態(tài)就由 pending -> rejected;當前的值為接收的值
then
class MyPromise { constructor(fn){ if(typeof fn !== 'function') { throw new TypeError(`MyPromise fn ${fn} is not a function`) } this.state = 'pending'; this.value = void 0; fn(this.resolve.bind(this),this.reject.bind(this)) } resolve(value){ if(this.state !== 'pending') return; this.state = 'fulfilled'; this.value = value } reject(reason){ if(this.state !== 'pending') return; this.state = 'rejected'; this.value = reason } then(fulfilled,rejected){ if (typeof fulfilled !== 'function' && typeof rejected !== 'function' ) { return this; } if (typeof fulfilled !== 'function' && this.state === 'fulfilled' || typeof rejected !== 'function' && this.state === 'rejected') { return this; } return new MyPromise((resolve,reject)=>{ if(fulfilled && typeof fulfilled === 'function' && this.state === 'fulfilled'){ let result = fulfilled(this.value); if(result && typeof result.then === 'function'){ return result.then(resolve,reject) }else{ resolve(result) } } if(rejected && typeof rejected === 'function' && this.state === 'rejected'){ let result = rejected(this.value); if(result && typeof result.then === 'function'){ return result.then(resolve,reject) }else{ resolve(result) } } }) } }
then的實現(xiàn)比較關(guān)鍵,首先有兩個判斷,第一個判斷傳的兩個參數(shù)是否都是函數(shù),如果部不是return this執(zhí)行下一步操作。
第二個判斷的作用是,比如,現(xiàn)在狀態(tài)從pending -> rejected;但是中間代碼中有許多個.then的操作,我們需要跳過這些操作執(zhí)行.catch的代碼。如下面的代碼,執(zhí)行結(jié)果只會打印1
new Promise((resolve,reject)=>{ reject(1) }).then(()=>{ console.log(2) }).then(()=>{ console.log(3) }).catch((e)=>{ console.log(e) })
我們繼續(xù),接下來看到的是返回了一個新的promise,真正then的實現(xiàn)的確都是返回一個promise實例。這里不多說
下面有兩個判斷,作用是判斷是rejected還是fulfilled,首先看fulfilled,如果是fulfilled的話,首先執(zhí)行fulfilled函數(shù),并把當前的value值傳過去,也就是下面這步操作,res就是傳過去的value值,并執(zhí)行了(res)=>{console.log(res)}這段代碼;執(zhí)行完成之后我們得到了result;也就是2這個結(jié)果,下面就是判斷當前結(jié)果是否是一個promise實例了,也就是下面注釋了的情況,現(xiàn)在我們直接執(zhí)行resolve(result);
new Promise((resolve,reject)=>{ resolve(1) }).then((res)=>{ console.log(res) return 2 //return new Promise(resolve=>{}) })
剩下的就不多說了,可以debugger看看執(zhí)行結(jié)果
catch
class MyPromise { ... catch(rejected){ return this.then(null,rejected) } }
完整代碼
class MyPromise { constructor(fn){ if(typeof fn !== 'function') { throw new TypeError(`MyPromise fn ${fn} is not a function`) } this.state = 'pending'; this.value = void 0; fn(this.resolve.bind(this),this.reject.bind(this)) } resolve(value){ if(this.state !== 'pending') return; this.state = 'fulfilled'; this.value = value } reject(reason){ if(this.state !== 'pending') return; this.state = 'rejected'; this.value = reason } then(fulfilled,rejected){ if (typeof fulfilled !== 'function' && typeof rejected !== 'function' ) { return this; } if (typeof fulfilled !== 'function' && this.state === 'fulfilled' || typeof rejected !== 'function' && this.state === 'rejected') { return this; } return new MyPromise((resolve,reject)=>{ if(fulfilled && typeof fulfilled === 'function' && this.state === 'fulfilled'){ let result = fulfilled(this.value); if(result && typeof result.then === 'function'){ return result.then(resolve,reject) }else{ resolve(result) } } if(rejected && typeof rejected === 'function' && this.state === 'rejected'){ let result = rejected(this.value); if(result && typeof result.then === 'function'){ return result.then(resolve,reject) }else{ resolve(result) } } }) } catch(rejected){ return this.then(null,rejected) } }
測試
new MyPromise((resolve,reject)=>{ console.log(1); //reject(2) resolve(2) console.log(3) setTimeout(()=>{console.log(4)},0) }).then(res=>{ console.log(res) return new MyPromise((resolve,reject)=>{ resolve(5) }).then(res=>{ return res }) }).then(res=>{ console.log(res) }).catch(e=>{ console.log('e',e) })
執(zhí)行結(jié)果:
> 1
> 3
> 2
> 5
> 4
原生promise
new Promise((resolve,reject)=>{ console.log(1); //reject(2) resolve(2) console.log(3) setTimeout(()=>{console.log(4)},0) }).then(res=>{ console.log(res) return new Promise((resolve,reject)=>{ resolve(5) }).then(res=>{ return res }) }).then(res=>{ console.log(res) }).catch(e=>{ console.log('e',e) })
執(zhí)行結(jié)果:
> 1
> 3
> 2
> 5
> 4
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
- node.js中使用q.js實現(xiàn)api的promise化
- 基于promise.js實現(xiàn)nodejs的promises庫
- nodejs中簡單實現(xiàn)Javascript Promise機制的實例
- JS 中使用Promise 實現(xiàn)紅綠燈實例代碼(demo)
- 淺談JavaScript中的對象及Promise對象的實現(xiàn)
- javascript使用Promise對象實現(xiàn)異步編程
- 舉例詳解JavaScript中Promise的使用
- JavaScript中的Promise使用詳解
- JavaScript Promise 用法
- JavaScript異步編程Promise模式的6個特性
相關(guān)文章
javascript substr和substring用法比較
在js中substring和substr都是用來截取字符串的,那么substring和substr之間的具體區(qū)別在哪里,有沒有區(qū)別呢,下面我來給各位詳細引用一些實例來介紹這些問題2009-06-06常常會用到的截取字符串substr()、substring()、slice()方法詳解
javascript中給我們提供三個截取字符串的方法,分別是:slice(),substring()和substr()。下面我們對這三個函數(shù)進行詳細說明和比較,需要的朋友可以參考下2015-12-12用js腳本控制asp.net下treeview的NodeCheck的實現(xiàn)代碼
根據(jù)TreeView2.js修改后的TreeView父節(jié)點與子節(jié)點的CheckBox聯(lián)動.2010-03-03使用JavaScript實現(xiàn)小球按照貝塞爾曲線運動
要在 JavaScript 中實現(xiàn)一個按照貝塞爾曲線運動的小球,關(guān)鍵是要掌握貝塞爾公式的基本原理和實現(xiàn)方式,以及使用 JavaScript 處理動畫和物理運算,感興趣的小伙伴跟著小編一起來看看吧2024-10-10