本文主要實(shí)現(xiàn) Promise 的 resolve治专,reject,以及 then 方法的鏈?zhǔn)秸{(diào)用配猫,并將會(huì)對(duì)完成的代碼進(jìn)行測(cè)試,最終實(shí)現(xiàn)下面的效果
new Promise((resolve,reject)=>{
resolve()
reject()
})
.then(res=>{console.log(res),(err)=>{console.log(err)}}
)
初步實(shí)現(xiàn)Promise
- 創(chuàng)建 Promise 類,添加resolve,reject 方法
class Promise {
constructor(executor){
if(typeof executor !== 'function'){
// 參數(shù)校驗(yàn)技即,參數(shù)必須是函數(shù)
throw new TypeError(`Promise resolver ${executor} is not a function`)
}
// 定義 resolve 函數(shù)和 reject 函數(shù)
const resolve = function(){}
const reject = function(){}
// 執(zhí)行傳入的函數(shù)
executor(resolve,reject)
}
}
module.exports = Promise;
- 完善 resolve,reject 方法
class Promise {
constructor(executor){
if(typeof executor !== 'function'){
// 參數(shù)校驗(yàn)樟遣,參數(shù)必須是函數(shù)
throw new TypeError(`Promise resolver ${executor} is not a function`)
}
// 初始化值
this.value = null
this.reason = null
this.status = 'pending'
const resolve = (value)=>{
// 成功后的操作:改變狀態(tài)而叼,成功后執(zhí)行回調(diào)
if(this.status === 'pendding'){
this.status = 'fulfilled'
this.value = value
}
}
const reject = (reason)=>{
// 失敗后的操作:改變狀態(tài),失敗后執(zhí)行回調(diào)
if(this.status === 'pendding'){
this.status = 'rejected'
this.reason = reason
}
}
// 執(zhí)行傳入的函數(shù)
executor(resolve,reject)
}
}
優(yōu)化代碼豹悬,綁定 this
class Promise {
constructor(executor){
if (typeof executor !== 'function') {
throw new TypeError(`Promise resolver ${executor} is not a function`)
}
// 初始化值葵陵,綁定 this,執(zhí)行傳入的回調(diào)
this.initialValue()
this.initBind()
// 防止發(fā)生錯(cuò)誤
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
initialValue() {
// 初始化值
this.value = null
this.reason = null
this.status = Promise.PENDING
}
// 定義 resolve 函數(shù)和 reject 函數(shù)
resolve(value) {
// 成功后的操作:改變狀態(tài)瞻佛,成功后執(zhí)行回調(diào)
if (this.status === Promise.PENDING) {
this.status = Promise.FULFILLED
this.value = value
}
}
reject(reason) {
// 失敗后的操作:改變狀態(tài)脱篙,失敗后執(zhí)行回調(diào)
if (this.status === Promise.PENDING) {
this.status = Promise.REJECTED
this.reason = reason
}
}
}
Promise.PENDING = 'pending'
Promise.FULFILLED = 'fulfilled'
Promise.REJECTED = 'rejected'
初步實(shí)現(xiàn) then 方法
在 promise 中,如果 then 方法未傳入?yún)?shù)伤柄,在接下來的 then 方法中依然是可以獲取結(jié)果的
new Promise((resolve,reject) => {
resolve(123)
})
.then()
.then(res=>{
console.log(res) // 輸出 123
})
想要實(shí)現(xiàn)值得穿透效果绊困,只需要每次將值傳出就可以了
then(onFulfilled, onRejected) {
// 值的穿透問題,參數(shù)校驗(yàn)
if (typeof onFulfilled !== 'function') {
onFulfilled = function (value) {
return value
}
}
if (typeof onRejected !== 'function') {
onRejected = function (reason) {
throw reason
}
}
if (this.status === Promise.FULFILLED) {
onFulfilled(this.value)
}
if (this.status === Promise.REJECTED) {
onRejected(this.reason)
}
}
實(shí)現(xiàn) then 方法的異步
then(onFulfilled, onRejected) {
// 值的穿透問題,參數(shù)校驗(yàn)
if (typeof onFulfilled !== 'function') {
onFulfilled = function (value) {
return value
}
}
if (typeof onRejected !== 'function') {
onRejected = function (reason) {
throw reason
}
}
if (this.status === Promise.FULFILLED) {
// 異步
setTimeout(() => {
onFulfilled(this.value)
})
}
if (this.status === Promise.REJECTED) {
setTimeout(() => {
onRejected(this.reason)
})
}
}
將then 中的回調(diào)添加到數(shù)組
class Promise {
constructor(executor) {
if (typeof executor !== 'function') {
throw new TypeError(`Promise resolver ${executor} is not a function`)
}
this.initialValue()
this.initBind()
// 原生 promise 中異常處理在 reject 函數(shù)中
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
initialValue() {
// 初始化值
this.value = null
this.reason = null
this.status = Promise.PENDING
// 添加成功和時(shí)報(bào)回調(diào)
+ this.onFulfilledCallbacks = []
+ this.onRejectedCallbacks = []
}
// 定義 resolve 函數(shù)和 reject 函數(shù)
resolve(value) {
// 成功后的操作:改變狀態(tài),成功后執(zhí)行回調(diào)
if (this.status === Promise.PENDING) {
this.status = Promise.FULFILLED
this.value = value
+ this.onFulfilledCallbacks.forEach(fn => {
+ fn(this.value)
+ })
}
}
reject(reason) {
// 失敗后的操作:改變狀態(tài)适刀,失敗后執(zhí)行回調(diào)
if (this.status === Promise.PENDING) {
this.status = Promise.REJECTED
this.reason = reason
+ this.onRejectedCallbacks.forEach(fn => {
+ fn(this.reason)
+ })
}
}
then(onFulfilled, onRejected) {
// 值得穿透問題,參數(shù)校驗(yàn)
if (typeof onFulfilled !== 'function') {
onFulfilled = function (value) {
return value
}
}
+ if (typeof onRejected !== 'function') {
+ onRejected = function (reason) {
+ throw reason
+ }
}
// 實(shí)現(xiàn)異步操作
+ if (this.status === Promise.FULFILLED) {
+ setTimeout(() => {
+ onFulfilled(this.value)
+ })
+ }
+ if (this.status === Promise.REJECTED) {
+ setTimeout(() => {
+ onRejected(this.reason)
+ })
+ }
// pending 狀態(tài)下將要執(zhí)行的函數(shù)放到數(shù)組中
+ if (this.status === Promise.PENDING) {
+ this.onFulfilledCallbacks.push((value) => {
+ setTimeout(()=>{
+ onFulfilled(value)
+ })
+ })
+ this.onRejectedCallbacks.push(reason=>{
+ setTimeout(()=>{
+ onRejected(reason)
+ })
+ })
}
}
}
Promise.PENDING = 'pending'
Promise.FULFILLED = 'fulfilled'
Promise.REJECTED = 'rejected'
實(shí)現(xiàn) then 方法返回一個(gè)新的 promise秤朗,可以在 resolve 中返回一個(gè)新的promise
class Promise {
constructor(executor) {
if (typeof executor !== 'function') {
throw new TypeError(`Promise resolver ${executor} is not a function`)
}
this.initialValue()
this.initBind()
// 原生 promise 中異常處理在 reject 函數(shù)中
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
initialValue() {
// 初始化值
this.value = null
this.reason = null
this.status = Promise.PENDING
// 添加成功和時(shí)報(bào)回調(diào)
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
}
// 定義 resolve 函數(shù)和 reject 函數(shù)
resolve(value) {
// 成功后的操作:改變狀態(tài),成功后執(zhí)行回調(diào)
if (this.status === Promise.PENDING) {
this.status = Promise.FULFILLED
this.value = value
this.onFulfilledCallbacks.forEach(fn => {
fn(this.value)
})
}
}
reject(reason) {
// 失敗后的操作:改變狀態(tài)笔喉,失敗后執(zhí)行回調(diào)
if (this.status === Promise.PENDING) {
this.status = Promise.REJECTED
this.reason = reason
this.onRejectedCallbacks.forEach(fn => {
fn(this.reason)
})
}
}
then(onFulfilled, onRejected) {
// 值的穿透問題,參數(shù)校驗(yàn)
if (typeof onFulfilled !== 'function') {
onFulfilled = function (value) {
return value
}
}
if (typeof onRejected !== 'function') {
onRejected = function (reason) {
throw reason
}
}
// 實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用取视,且改變后面的 then 的值,必須通過新的實(shí)例
let promise2 = new Promise((resolve, reject) => {
// 實(shí)現(xiàn)異步操作
if (this.status === Promise.FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
Promise.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === Promise.REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
Promise.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
// pending 狀態(tài)下將要執(zhí)行的函數(shù)放到數(shù)組中
if (this.status === Promise.PENDING) {
this.onFulfilledCallbacks.push((value) => {
setTimeout(() => {
try {
let x = onFulfilled(value)
Promise.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
})
this.onRejectedCallbacks.push(reason => {
setTimeout(() => {
try {
let x = onRejected(reason)
Promise.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
})
return promise2
}
}
Promise.PENDING = 'pending'
Promise.FULFILLED = 'fulfilled'
Promise.REJECTED = 'rejected'
Promise.resolvePromise = function (promise2, x, resolve, reject) {
// 避免鏈?zhǔn)叫?yīng)
if (promise2 === x) {
reject(new TypeError('Chaining circle detected for promise'))
}
let called = false
if (x instanceof Promise) {
// 判斷 x 是否為 promise
x.then(value => {
Promise.resolvePromise(promise2, value, resolve, reject)
}, reason => {
reject(reason)
})
} else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
// 判斷 x 是否為對(duì)象或者函數(shù)
try {
const then = x.then
if (typeof then === 'function') {
then.call(x, value => {
if (called) return
called = true
Promise.resolvePromise(promise2, value, resolve, reject)
}, reason => {
if (called) return
called = true
reject(reason)
})
} else {
if (called) return
called = true
resolve(x)
}
} catch (e) {
if (called) return
called = true
reject(e)
}
} else {
resolve(x)
}
}
測(cè)試
- 安裝測(cè)試工具
npm install promises-aplus-tests
// 用來測(cè)試自己的promise 符不符合promisesA+規(guī)范,mac用戶最前面加上sudo
- 添加測(cè)試代碼
Promise.defer = Promise.deferred = function () {
let dfd = {}
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
module.exports = Promise;
- 運(yùn)行測(cè)試代碼
promises-aplus-tests [js文件名]