1. Promise A+ 規(guī)范
官方英文地址:https://promisesaplus.com/
中文翻譯可參考 http://malcolmyu.github.io/malnote/2015/06/12/Promises-A-Plus/
2. 代碼實(shí)現(xiàn)
github地址:https://github.com/whu-luojian/Promise.git
// promise的狀態(tài)枚舉
const STATUS = {
PENDING: 0,
FULFILLED: 1,
REJECTED: 2
}
class Promise {
constructor(task) {
// promise初始狀態(tài)
this.status = STATUS.PENDING;
// resolve時(shí)返回的數(shù)據(jù)
this.resolveData = null;
// reject時(shí)返回的數(shù)據(jù)
this.rejectData = null;
// resolve和reject時(shí)執(zhí)行的回調(diào)隊(duì)列
// promise的resolve和reject為異步響應(yīng)時(shí)车荔,即調(diào)用then時(shí)promise為
// pending狀態(tài),則將傳入then的函數(shù)加入該隊(duì)列,等待promise resolve或
// reject時(shí)執(zhí)行該隊(duì)列
this.onFulfilledList = [];
this.onRejectedList = [];
/**
* promise成功平项,執(zhí)行onFulfilledList回調(diào)
* @param {*} data
*/
this.onResolve = (data) => {
if(this.status === STATUS.PENDING) {
this.status = STATUS.FULFILLED;
this.resolveData = data;
this.onFulfilledList.forEach(fn => {
fn(this.resolveData)
})
}
}
/**
* promise失敗倾剿,執(zhí)行onRejectedList回調(diào)
* @param {*} err
*/
this.onReject = (err) => {
if(this.status === STATUS.PENDING) {
this.status = STATUS.REJECTED;
this.rejectData = err;
this.onRejectedList.forEach(fn => {
fn(this.rejectData)
})
}
}
/**
* promise解析, 根據(jù)then 返回?cái)?shù)據(jù)類(lèi)型不同封裝不同的promise
* 返回栗菜,以便實(shí)現(xiàn)then的鏈?zhǔn)秸{(diào)用及Promise的thenable特性
* @param {*當(dāng)前then return數(shù)據(jù)} data
* @param {*當(dāng)前then的resolve} resolve
* @param {*當(dāng)前then的reject} reject
*/
this.resolvePromise = (data, resolve, reject) => {
// then return 的數(shù)據(jù)是一個(gè)promise
if(data instanceof Promise) {
if(data.status === STATUS.PENDING) {
data.then((val) => {
this.resolvePromise(val, resolve, reject);
}, reject)
} else if (data.status === STATUS.FULFILLED) {
resolve(data.resolveData)
} else {
reject(data.rejectData)
}
}
// then return的是一個(gè)對(duì)象,若對(duì)象具有then方法骡男,則可使用此方法作為新的then
// Promise的thenable特性基于此
else if(data !== null && data instanceof Object) {
try {
let then = data.then
if(then instanceof Function) {
then.call(data, (val) => {
this.resolvePromise(val, resolve, reject);
}, reject)
} else {
resolve(data)
}
} catch (err) {
reject(err)
}
}
// then return 的是基本數(shù)據(jù)或undefined
else {
resolve(data)
}
}
// 執(zhí)行傳入的任務(wù)task
try {
task(this.onResolve.bind(this), this.onReject.bind(this))
} catch (err) {
this.onReject(err)
}
}
/**
* then回調(diào)赃蛛,返回一個(gè)promise
* 說(shuō)明:傳入then的參數(shù)不是函數(shù)的話(huà)庇茫,直接忽略港粱,及在返回的新promise中直接resolve或reject目前
* promise的數(shù)據(jù),傳入then的參數(shù)是函數(shù)的話(huà)旦签,則直接已目前promise的數(shù)據(jù)為參數(shù)執(zhí)行該函數(shù)查坪,并
* 根據(jù)函數(shù)返回值情況確定新promise的狀態(tài)
* @param {*成功} onFulfilled
* @param {*失敗} onRejected
*/
then(onFulfilled, onRejected) {
let promise;
// pending狀態(tài)下將傳入then的函數(shù)加入promise對(duì)應(yīng)的回調(diào)隊(duì)列
// 等待promise狀態(tài)改變后執(zhí)行
if(this.status === STATUS.PENDING) {
promise = new Promise((resolve, reject) => {
this.onFulfilledList.push(() => {
// 傳入then的參數(shù)不是函數(shù)則忽略
if(!(onFulfilled instanceof Function)) {
resolve(this.resolveData)
} else {
let data = onFulfilled(this.resolveData)
this.resolvePromise(data, resolve, reject)
}
})
this.onRejectedList.push(() => {
// 傳入then的參數(shù)不是函數(shù)則忽略
if(!(onRejected instanceof Function)) {
reject(this.rejectData)
} else {
let data = onRejected(this.rejectData)
this.resolvePromise(data, resolve, reject)
}
})
})
}
// fulfilled狀態(tài)下以promise的resolveData為參數(shù)執(zhí)行傳入then的
// 成功回調(diào)函數(shù),再根據(jù)此函數(shù)的返回值封裝新的promise返回
else if (this.status === STATUS.FULFILLED) {
promise = new Promise((resolve, reject) => {
// 傳入then的參數(shù)不是函數(shù)則忽略宁炫,直接resolve
if(!(onFulfilled instanceof Function)) {
resolve(this.resolveData)
} else {
let data = onFulfilled(this.resolveData)
this.resolvePromise(data, resolve, reject)
}
})
}
// rejected狀態(tài)類(lèi)似fulfilled狀態(tài)
else {
promise = new Promise((resolve, reject) => {
// 傳入then的參數(shù)不是函數(shù)則忽略偿曙,直接reject
if(!(onRejected instanceof Function)) {
reject(this.rejectData)
} else {
let data = onRejected(this.rejectData)
this.resolvePromise(data, resolve, reject)
}
})
}
return promise
}
/**
* catch方法
* @param {*reject函數(shù)} rejectFn
*/
catch(rejectFn) {
//不是函數(shù)直接返回
if(!(rejectFn instanceof Function)) {
return
}
if(this.status === STATUS.PENDING) {
this.onRejectedList.push(() => {
// 沒(méi)有錯(cuò)誤信息則不執(zhí)行catch中的函數(shù)
if(this.rejectData !== null) {
rejectFn(this.rejectData)
}
})
} else if (this.status = STATUS.REJECTED) {
// 沒(méi)有錯(cuò)誤信息則不執(zhí)行catch中的函數(shù)
if(this.rejectData !== null) {
rejectFn(this.rejectData)
}
}
}
/**
* resolve方法,
* value為promise直接返回返回一個(gè)以value為resolveData的完成態(tài)promise
* @param {*} value
*/
static resolve(value) {
if(value instanceof Promise) {
return value
}
return new Promise((resolve, reject) => {
resolve(value)
})
}
/**
* reject方法淋淀,類(lèi)似resolve方法
* @param {*} value
*/
static reject(value) {
if(value instanceof Promise) {
return value
}
return new Promise((resolve, reject) => {
reject(value)
})
}
/**
* all方法遥昧,返回一個(gè)新的promise
* 參數(shù)為promise數(shù)組
* 成功的時(shí)候返回的是一個(gè)結(jié)果數(shù)組,而失敗的時(shí)候則返回最先被reject失敗狀態(tài)的值朵纷。
* @param {*} promiseArray
*/
static all(promiseArray) {
if(!(promiseArray instanceof Array)) {
throw new TypeError("parameter must be array")
}
let result = []
let i = 0
return new Promise((resolve, reject) => {
if(promiseArray.length === 0) {
resolve(result)
} else {
promiseArray.forEach((item, index) => {
if(item instanceof Promise) {
item.then(res => {
result[index] = res
i++
if(i === promiseArray.length) {
resolve(result)
}
}, err => {
reject(err)
})
}
// 如果傳入的不是promise炭臭,則直接作為結(jié)果填入結(jié)果數(shù)組中
else {
result[index] = item
i++
if(i === promiseArray.length) {
resolve(result)
}
}
})
}
})
}
/**
* race方法,返回一個(gè)新的promise
* 參數(shù)為promise數(shù)組
* 返回最先執(zhí)行完的promise的結(jié)果袍辞,不論resolve還是reject
* @param {*} promiseArray
*/
static race(promiseArray) {
if(!(promiseArray instanceof Array)) {
throw new TypeError("parameter must be array")
}
// 標(biāo)識(shí)符鞋仍,有一個(gè)promise執(zhí)行完成設(shè)為true,返回結(jié)果
let flag = false
return new Promise((resolve, reject) => {
promiseArray.forEach((item) => {
if(item instanceof Promise) {
item.then(res => {
if(!flag) {
flag = true
resolve(res)
}
}, err => {
if(!flag) {
flag = true
reject(err)
}
})
}
// 如果傳入的不是promise搅吁,則直接作為結(jié)果
else {
if(!flag) {
flag = true
resolve(item)
}
}
})
})
}
}