手書きPromise——SE 6によるPromise実現(詳細コメント含む)
7930 ワード
1.Promise A+仕様公式英語アドレス:https://promisesaplus.com/ 中国語の翻訳は参考にできます。http://malcolmyu.github.io/malnote/2015/06/12/Promises-A-Plus/ 2.コード実現
githubアドレス:https://github.com/whu-luojian/Promise.git
githubアドレス:https://github.com/whu-luojian/Promise.git
// promise
const STATUS = {
PENDING: 0,
FULFILLED: 1,
REJECTED: 2
}
class Promise {
constructor(task) {
// promise
this.status = STATUS.PENDING;
// resolve
this.resolveData = null;
// reject
this.rejectData = null;
// resolve reject
// promise resolve reject , then promise
// pending , then , promise resolve
// reject
this.onFulfilledList = [];
this.onRejectedList = [];
/**
* promise , onFulfilledList
* @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 , onRejectedList
* @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 , then promise
* , then Promise thenable
* @param {* then return } data
* @param {* then resolve} resolve
* @param {* then reject} reject
*/
this.resolvePromise = (data, resolve, reject) => {
// then return 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 , 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 undefined
else {
resolve(data)
}
}
// task
try {
task(this.onResolve.bind(this), this.onReject.bind(this))
} catch (err) {
this.onReject(err)
}
}
/**
* then , promise
* : then , , promise resolve reject
* promise , then , promise ,
* promise
* @param {* } onFulfilled
* @param {* } onRejected
*/
then(onFulfilled, onRejected) {
let promise;
// pending then promise
// promise
if(this.status === STATUS.PENDING) {
promise = new Promise((resolve, reject) => {
this.onFulfilledList.push(() => {
// then
if(!(onFulfilled instanceof Function)) {
resolve(this.resolveData)
} else {
let data = onFulfilled(this.resolveData)
this.resolvePromise(data, resolve, reject)
}
})
this.onRejectedList.push(() => {
// then
if(!(onRejected instanceof Function)) {
reject(this.rejectData)
} else {
let data = onRejected(this.rejectData)
this.resolvePromise(data, resolve, reject)
}
})
})
}
// fulfilled promise resolveData then
// , promise
else if (this.status === STATUS.FULFILLED) {
promise = new Promise((resolve, reject) => {
// then , resolve
if(!(onFulfilled instanceof Function)) {
resolve(this.resolveData)
} else {
let data = onFulfilled(this.resolveData)
this.resolvePromise(data, resolve, reject)
}
})
}
// rejected fulfilled
else {
promise = new Promise((resolve, reject) => {
// then , reject
if(!(onRejected instanceof Function)) {
reject(this.rejectData)
} else {
let data = onRejected(this.rejectData)
this.resolvePromise(data, resolve, reject)
}
})
}
return promise
}
/**
* catch
* @param {*reject } rejectFn
*/
catch(rejectFn) {
//
if(!(rejectFn instanceof Function)) {
return
}
if(this.status === STATUS.PENDING) {
this.onRejectedList.push(() => {
// catch
if(this.rejectData !== null) {
rejectFn(this.rejectData)
}
})
} else if (this.status = STATUS.REJECTED) {
// catch
if(this.rejectData !== null) {
rejectFn(this.rejectData)
}
}
}
/**
* resolve ,
* value promise value resolveData promise
* @param {*} value
*/
static resolve(value) {
if(value instanceof Promise) {
return value
}
return new Promise((resolve, reject) => {
resolve(value)
})
}
/**
* reject , resolve
* @param {*} value
*/
static reject(value) {
if(value instanceof Promise) {
return value
}
return new Promise((resolve, reject) => {
reject(value)
})
}
/**
* all , promise
* promise
* , reject 。
* @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,
else {
result[index] = item
i++
if(i === promiseArray.length) {
resolve(result)
}
}
})
}
})
}
/**
* race , promise
* promise
* promise , resolve reject
* @param {*} promiseArray
*/
static race(promiseArray) {
if(!(promiseArray instanceof Array)) {
throw new TypeError("parameter must be array")
}
// , promise true,
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,
else {
if(!flag) {
flag = true
resolve(item)
}
}
})
})
}
}