Skip to content

Instantly share code, notes, and snippets.

@jasonliao
Last active August 27, 2020 03:38
Show Gist options
  • Save jasonliao/e5aadfa5f2fb34f0d88ea2ff0e1b2b68 to your computer and use it in GitHub Desktop.
Save jasonliao/e5aadfa5f2fb34f0d88ea2ff0e1b2b68 to your computer and use it in GitHub Desktop.
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