Last active
August 27, 2020 03:38
-
-
Save jasonliao/e5aadfa5f2fb34f0d88ea2ff0e1b2b68 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const PromiseStatus = Symbol(); | |
const PromiseValue = Symbol(); | |
const resolveCallback = Symbol(); | |
const rejectCallback = Symbol(); | |
const resolve = Symbol(); | |
const reject = Symbol(); | |
const PROMISE_STATES = { | |
PENDING: Symbol(), | |
FULFILLED: Symbol(), | |
REJECTED: Symbol() | |
}; | |
class Promise { | |
constructor(fn) { | |
if (typeof fn !== "function") { | |
throw new TypeError("Promise resolver undefined is not a function"); | |
} | |
this[PromiseStatus] = PROMISE_STATES.PENDING; | |
this[PromiseValue] = undefined; | |
this[resolveCallback] = []; | |
this[rejectCallback] = []; | |
// 使用 try catch 是因为防止 fn 执行出错 | |
try { | |
fn(this[resolve], this[reject]); | |
} catch (e) { | |
this[reject](e); | |
} | |
} | |
[resolve] = value => { | |
if (this[PromiseStatus] === PROMISE_STATES.PENDING) { | |
this[PromiseStatus] = PROMISE_STATES.FULFILLED; | |
this[PromiseValue] = value; | |
this[resolveCallback].forEach(fn => fn(value)); | |
} | |
}; | |
[reject] = reason => { | |
if (this[PromiseStatus] === PROMISE_STATES.PENDING) { | |
this[PromiseStatus] = PROMISE_STATES.REJECTED; | |
this[PromiseValue] = reason; | |
this[rejectCallback].forEach(fn => fn(reason)); | |
} | |
}; | |
then(onResolve, onRejcet) { | |
onResolve = | |
typeof onResolve === "function" | |
? onResolve | |
: function(value) { | |
return value; | |
}; | |
onRejcet = | |
typeof onRejcet === "function" | |
? onRejcet | |
: function(reason) { | |
return reason; | |
}; | |
if (this[PromiseStatus] === PROMISE_STATES.PENDING) { | |
return new Promise((resolve, reject) => { | |
this[resolveCallback].push(value => { | |
try { | |
const result = onResolve(value); | |
if (result instanceof Promise) { | |
result.then(resolve, reject); | |
} | |
resolve(result); | |
} catch (e) { | |
reject(e); | |
} | |
}); | |
this[rejectCallback].push(reason => { | |
try { | |
const result = onRejcet(reason); | |
if (result instanceof Promise) { | |
result.then(resolve, reject); | |
} | |
} catch (e) { | |
reject(e); | |
} | |
}); | |
}); | |
} | |
if (this[PromiseStatus] === PROMISE_STATES.FULFILLED) { | |
return new Promise((resolve, reject) => { | |
try { | |
const result = onResolve(this[PromiseValue]); | |
if (result instanceof Promise) { | |
result.then(resolve, reject); | |
} | |
resolve(result); | |
} catch (e) { | |
reject(e); | |
} | |
}); | |
} | |
if (this[PromiseStatus] === PROMISE_STATES.REJECTED) { | |
return new Promise((resolve, reject) => { | |
try { | |
const result = onRejcet(this[PromiseValue]); | |
if (result instanceof Promise) { | |
result.then(resolve, reject); | |
} | |
} catch (e) { | |
reject(e); | |
} | |
}); | |
} | |
} | |
catch(onReject) { | |
return this.then(null, onReject); | |
} | |
static resolve(param) { | |
if (param instanceof Promise) { | |
return param; | |
} | |
return new Promise((resolve, reject) => { | |
resolve(param); | |
}); | |
} | |
static reject(reason) { | |
return new Promise((resolve, reject) => { | |
reject(reason); | |
}); | |
} | |
static all(arr) { | |
return new Promise((resolve, reject) => { | |
let result = []; | |
let index = 0; | |
if (arr.length === 0) { | |
resolve(result); | |
} else { | |
const processValue = (i, value) => { | |
result[i] = value; | |
if (i === arr.length - 1) { | |
resolve(result); | |
} | |
}; | |
for (let i = 0; i < arr.length; i++) { | |
Promise.resolve(arr[i]).then( | |
value => { | |
processValue(i, value); | |
}, | |
reason => { | |
return reject(reason); | |
} | |
); | |
} | |
} | |
}); | |
} | |
static race(arr) { | |
return new Promise((resolve, reject) => { | |
for (let i = 0; i < arr.length; i++) { | |
Promise.resolve(arr[i]).then( | |
value => { | |
return resolve(value); | |
}, | |
reason => { | |
return reject(reason); | |
} | |
); | |
} | |
}); | |
} | |
} | |
export default Promise; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment