JavaScript手寫(xiě)Promise核心原理
準(zhǔn)備
- 首先,
promise
有三種狀態(tài):pending
fulfilled
rejected
; promise
在實(shí)例化操作中, 有兩個(gè)改變狀態(tài)的方法,分別為resolve
,reject
;promise
有很多方法,詳情請(qǐng)見(jiàn)mdn
, 本篇文章先實(shí)現(xiàn)promise
的核心api
:then
和catch
;
我們使用 es6
提供的 class
來(lái)實(shí)現(xiàn)
class MyPromise { // 準(zhǔn)備三個(gè)狀態(tài) static PENDING = 'pending'; static FULFILLED = 'fulfilled'; static REJECTED = 'rejected'; constructor(executor) { this.status = MyPromise.PENDING; // 表示promise的狀態(tài) this.value = null; // 表示promise的值 try { executor(this.resolve.bind(this), this.reject.bind(this)) } catch (error) { this.reject(error) } } resolve() { } reject() { } }
在這里 executor
就是傳遞過(guò)來(lái)的函數(shù),可以接收 resolve
和reject
,這里將內(nèi)部的兩個(gè)方法給傳入,如果在調(diào)用的過(guò)程中報(bào)錯(cuò)了會(huì)調(diào)用reject
方法
完善 resolve/reject
他們做的工作分為以下幾部
- 將狀態(tài)改為
pending
為fulfilled
或rejected
- 可以接受一個(gè)值為當(dāng)前的
promise
的value
resolve(value) { if (this.status === MyPromise.PENDING) { this.status = MyPromise.FULFILLED; this.value = value } } reject(value) { if (this.status === MyPromise.PENDING) { this.status = MyPromise.REJECTED; this.value = value } }
then
then
函數(shù)可以接受兩個(gè)參數(shù),分別為成功的回調(diào)函數(shù)和失敗的回調(diào)函數(shù),并且回調(diào)函數(shù)的默認(rèn)為一個(gè)函數(shù)
- 狀態(tài)為
fulfilled
執(zhí)行第一個(gè)回調(diào),rejected
執(zhí)行第二個(gè)回調(diào) - 回調(diào)函數(shù)中給傳入當(dāng)前的
value
then
的執(zhí)行為異步的
then(onFulfilled, onRejected) { if (typeof onFulfilled !== 'function') { onFulfilled = value => value } if (typeof onFulfilled !== 'function') { onRejected = value => value } if (this.status === MyPromise.FULFILLED) { setTimeout(() => { onFulfilled(this.value) }) } if (this.status === MyPromise.REJECTED) { setTimeout(() => { onRejected(this.value) }) } }
驗(yàn)證一下:
console.log(1) new MyPromise((resolve, reject) => { console.log(2) resolve('成功') }).then(res => console.log(res)) console.log(3) // 打印 1 2 3 成功
當(dāng)promise
里面有異步代碼的時(shí)候,這個(gè)時(shí)候運(yùn)行到.then
方法 狀態(tài)為pending
,下來(lái)增加一下異步任務(wù)的處理
異步處理
當(dāng)狀態(tài)為pending
的時(shí)候,表示執(zhí)行的是異步任務(wù),這個(gè)時(shí)候我們可以增加一個(gè)callback
,把異步執(zhí)行的內(nèi)容添加到這個(gè)callback
中,當(dāng)執(zhí)行完異步代碼的時(shí)候,會(huì)執(zhí)行異步函數(shù)的callback
的任務(wù)
constructor(executor) { // ... this.callbacks = []; // 用來(lái)存儲(chǔ)回調(diào)函數(shù)的容器 // ... } resolve(value) { // ... this.callbacks.forEach(({ onFulfilled }) => onFulfilled(value)) // 當(dāng)執(zhí)行到這里的時(shí)候 如果有onFulfilled 就說(shuō)明已經(jīng)執(zhí)行完then方法給容器添加內(nèi)容了。把resolve的值傳遞給onFulfilled } reject(value) { // ... this.callbacks.forEach(({ onRejected }) => onRejected(value)) // 當(dāng)執(zhí)行到這里的時(shí)候 如果有onRejected 就說(shuō)明已經(jīng)執(zhí)行完then方法給容器添加內(nèi)容了。把reject的值傳遞給onFulfilled } then(onFulfilled, onRejected) { // ... if (this.status === MyPromise.PENDING) { this.callbacks.push({ onFulfilled: value => { setTimeout(() => { onFulfilled(value) }) }, onRejected: value => { setTimeout(() => { onRejected(value) }) } }) } }
驗(yàn)證一下:
new MyPromise((resolve, reject) => { setTimeout(() => { resolve('成功') }) }).then(res => console.log(res)) // 打印 成功
then
函數(shù)可以鏈?zhǔn)秸{(diào)用,接下來(lái)我們完善一下
鏈?zhǔn)秸{(diào)用
鏈?zhǔn)秸{(diào)用的核心就是返回一個(gè)新的 promise
,當(dāng)成功調(diào)用的時(shí)候調(diào)用新的promise
的resolve
,失敗reject
,并且鏈?zhǔn)秸{(diào)用會(huì)把前一個(gè)的返回值當(dāng)作下一個(gè)的 resolve
的狀態(tài)
then(onFulfilled, onRejected) { if (typeof onFulfilled !== 'function') { onFulfilled = value => value } if (typeof onFulfilled !== 'function') { onRejected = value => value } return new MyPromise((resolve, reject) => { if (this.status === MyPromise.FULFILLED) { setTimeout(() => { const result = onFulfilled(this.value) resolve(result) }) } if (this.status === MyPromise.REJECTED) { setTimeout(() => { const result = onRejected(this.value) resolve(result) }) } if (this.status === MyPromise.PENDING) { this.callbacks.push({ onFulfilled: value => { setTimeout(() => { const result = onFulfilled(value) resolve(result) }) }, onRejected: value => { setTimeout(() => { const result = onRejected(value) resolve(result) }) } }) } }) }
驗(yàn)證一下:
new MyPromise((resolve, reject) => { setTimeout(() => { reject('失敗') }) }).then(res => res, err => err).then(res => console.log(res)) // 打印 失敗
如果.then
的回調(diào)函數(shù)返回的是promise
的情況也要做個(gè)處理
邊界處理
實(shí)現(xiàn)前:
new MyPromise((resolve, reject) => { setTimeout(() => { resolve('成功') }) }).then( res => new MyPromise((resolve, reject) => { resolve(res) }), err => err ).then(res => console.log(res)) // 打印 { "status": "fulfilled", "value": "成功", "callbacks": [] }
當(dāng)判斷返回值為 MyPromise
的時(shí)候,需要手動(dòng)調(diào)用 .then
的方法取他的值,并且吧當(dāng)前的 promise
的改變狀態(tài)的函數(shù)透出給 then
方法
then(onFulfilled, onRejected) { if (typeof onFulfilled !== 'function') { onFulfilled = value => value } if (typeof onFulfilled !== 'function') { onRejected = value => value } return new MyPromise((resolve, reject) => { if (this.status === MyPromise.FULFILLED) { setTimeout(() => { const result = onFulfilled(this.value) if (result instanceof MyPromise) { result.then(resolve, reject) } else { resolve(result) } }) } if (this.status === MyPromise.REJECTED) { setTimeout(() => { const result = onRejected(this.value) if (result instanceof MyPromise) { result.then(resolve, reject) } else { resolve(result) } }) } if (this.status === MyPromise.PENDING) { this.callbacks.push({ onFulfilled: value => { setTimeout(() => { const result = onFulfilled(value) if (result instanceof MyPromise) { result.then(resolve, reject) } else { resolve(result) } }) }, onRejected: value => { setTimeout(() => { const result = onRejected(value) if (result instanceof MyPromise) { result.then(resolve, reject) } else { resolve(result) } }) } }) } }) }
驗(yàn)證:
new MyPromise((resolve, reject) => { setTimeout(() => { resolve('成功') }) }).then( res => new MyPromise((resolve, reject) => { resolve(res) }), err => err ).then(res => console.log(res)) // 打印 成功
到這里 .then
方法就實(shí)現(xiàn)差不多了,接下來(lái)實(shí)現(xiàn) catch
方法
catch
catch 方法可以處理拒絕的狀態(tài)和錯(cuò)誤的狀態(tài):
catch(onFulfilled) { if (typeof onFulfilled !== 'function') { onFulfilled = value => value } return new MyPromise((resolve, reject) => { if (this.status === MyPromise.REJECTED) { setTimeout(() => { const result = onFulfilled(this.value) if (result instanceof MyPromise) { result.then(resolve, reject) } else { resolve(result) } }) } }) }
驗(yàn)證:
new MyPromise((resolve, reject) => { reject('失敗') }).catch(res=> console.log(res)) // 打印 失敗
道理其實(shí)和 then
是相同的,到這里主功能基本上就差不多了,但是有很多重復(fù)的地方,優(yōu)化一下
優(yōu)化后完整代碼
class MyPromise { // 準(zhǔn)備三個(gè)狀態(tài) static PENDING = 'pending'; static FULFILLED = 'fulfilled'; static REJECTED = 'rejected'; constructor(executor) { this.status = MyPromise.PENDING; // 表示promise的狀態(tài) this.value = null; // 表示promise的值 this.callbacks = []; try { executor(this.resolve.bind(this), this.reject.bind(this)) } catch (error) { console.log(error) this.reject(error) } } resolve(value) { if (this.status === MyPromise.PENDING) { this.status = MyPromise.FULFILLED; this.value = value } this.callbacks.forEach(({ onFulfilled }) => onFulfilled(value)) } reject(value) { if (this.status === MyPromise.PENDING) { this.status = MyPromise.REJECTED; this.value = value } this.callbacks.forEach(({ onRejected }) => onRejected(value)) } parse({ callback, resolve, reject, value = this.value }) { setTimeout(() => { const result = callback(value) if (result instanceof MyPromise) { result.then(resolve, reject) } else { resolve(result) } }) } then(onFulfilled, onRejected) { if (typeof onFulfilled !== 'function') { onFulfilled = value => value } if (typeof onFulfilled !== 'function') { onRejected = value => value } return new MyPromise((resolve, reject) => { if (this.status === MyPromise.FULFILLED) { this.parse({ callback: onFulfilled, resolve, reject }) } if (this.status === MyPromise.REJECTED) { this.parse({ callback: onRejected, resolve, reject }) } if (this.status === MyPromise.PENDING) { this.callbacks.push({ onFulfilled: value => { this.parse({ callback: onFulfilled, resolve, reject, value }) }, onRejected: value => { this.parse({ callback: onRejected, resolve, reject, value }) } }) } }) } catch(onFulfilled) { if (typeof onFulfilled !== 'function') { onFulfilled = value => value } return new MyPromise((resolve, reject) => { if (this.status === MyPromise.REJECTED) { this.parse({ callback: onFulfilled, resolve, reject }) } }) } }
到此這篇關(guān)于JavaScript手寫(xiě)Promise核心原理的文章就介紹到這了,更多相關(guān)JavaScript Promise內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
layui獲取選中行數(shù)據(jù)的實(shí)例講解
今天小編就為大家分享一篇layui獲取選中行數(shù)據(jù)的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08利用JavaScript將普通數(shù)字轉(zhuǎn)換為帶有千分位分隔符格式的多種實(shí)現(xiàn)方法
如何利用 JavaScript 將普通數(shù)字轉(zhuǎn)換為帶有千分位分隔符的格式,我們將介紹多種方法,包括使用內(nèi)置的 toLocaleString() 方法、Intl.NumberFormat 對(duì)象以及自定義函數(shù)來(lái)實(shí)現(xiàn)數(shù)字格式化,需要的朋友可以參考下2023-12-12利用element-ui實(shí)現(xiàn)遠(yuǎn)程搜索兩種實(shí)現(xiàn)方式
這篇文章主要介紹了利用element-ui的兩種遠(yuǎn)程搜索實(shí)現(xiàn)代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-12-12JS對(duì)話框_JS模態(tài)對(duì)話框showModalDialog用法總結(jié)
本篇文章主要是對(duì)JS對(duì)話框_JS模態(tài)對(duì)話框showModalDialog的用法進(jìn)行了總結(jié)介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2014-01-01layer彈出層父子頁(yè)面事件相互調(diào)用方法
今天小編就為大家分享一篇layer彈出層父子頁(yè)面事件相互調(diào)用方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08JavaScript中獲取當(dāng)前時(shí)間yyyymmddhhmmss的六種實(shí)現(xiàn)方式
js中提供了一個(gè)Date對(duì)象供我們獲取當(dāng)前時(shí)間,下面這篇文章主要給大家介紹了關(guān)于JavaScript中獲取當(dāng)前時(shí)間yyyymmddhhmmss的六種實(shí)現(xiàn)方式,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12