class MyPromise {
constructor(callback) {
this.init();
try {
// 防止修改this指向
callback(this.resolve.bind(this, this), this.reject.bind(this, this));
} catch (e) {
this._errinfo = e;
}
}
init () {
// 回调仓库
this._store = [];
// 处理在 new MyPromise((resolve, reject) => {没有异步的情况下调用resolve/reject,或者这里的同步代码报错}),
// 异步操作里面的报错是同步try/catch捕捉不了的。
// 比如 new MyPromise(() => setTimeout(() => undefinedMethod())) 这个定时器里面的报错是不会通过传递到catch回调的
// 除非是这样 new MyPromise(() => undefinedMethod())在同步执行下报错,才会传递给catch回调
this._errinfo = '';
this._succinfo = '';
// a = new MyPromise((resolve, reject) => setTimeout(() => resolve(), 1230)); a.then(() => ...) 异步一下
// 让then/catch/finally都挂载好
this._timer = null;
// 表示是否调用过 resolve 或者 reject 函数
// 避免在 a = new MyPromise((resolve, reject) => setTimeout(() => resolve(), 1230)); a.then(() => ...) 的时候,
// 不会正常调用then/catch或者finally
this._start = false;
}
resolve (ctx, succ) {
ctx._start = true;
// 出现在没有在异步下直接调用resolve
if (ctx._store.length === 0) {
ctx._succinfo = succ;
return;
}
let cb, res;
while (cb = ctx._store.shift()) {
if (cb.type === 'THEN') {
try {
res = cb.callback(res || succ);
// 返回新的my promise实例的时候,将剩余的回调拷贝过去
if (res instanceof MyPromise) {
while(cb = ctx._store.shift()) {res[cb.type.toLowerCase()](cb.callback)}
break;
}
ctx._succinfo = res;
} catch (e) {
ctx.reject(ctx, e);
break;
}
}
if (ctx._handleFinally(cb) === false) {
break;
}
}
}
reject (ctx, err) {
ctx._start = true;
// 出现在没有在异步下直接调用reject
if (ctx._store.length === 0) {
ctx._errinfo = err;
return;
}
let cb, res;
while (cb = ctx._store.shift()) {
if (cb.type === 'CATCH') {
try {
res = cb.callback(res || err);
ctx.resolve(ctx);
break;
} catch (e) {
res = e;
ctx._errinfo = e;
}
}
if (ctx._handleFinally(cb) === false) {
break;
}
}
}
_handleFinally (storeItem) {
if (storeItem.type === "FINALLY") {
try {
storeItem.callback();
} catch (e) {
this.reject(this, e);
return false;
}
}
}
then (callback) {
this._addCallback('THEN', callback);
this._deferHandle(() => {
this.resolve(this, this._succinfo);
this._succinfo = '';
});
return this;
}
catch (callback) {
this._addCallback('CATCH', callback);
this._deferHandle(() => {
this.reject(this, this._errinfo);
this._errinfo = '';
});
return this;
}
finally (callback) {
this._addCallback('FINALLY', callback);
this._deferHandle(() => this.resolve(this));
return this;
}
_deferHandle(callback) {
if (!this._timer && this._start) {
this._timer = setTimeout(() => {
callback();
this._timer = null;
});
}
}
_addCallback (typeName, callback) {
this._store.push({
type: typeName,
callback: callback
});
}
// 参数解构, 有数组解构写法之后,这个就不需要了
// static separate (callback) {
// return (args) => callback.apply(null, args);
// }
static all (pros) {
return new MyPromise((res, rej) => {
let args = [],
book = [],
isCatch = false,
handleResolve, handleCatch;
handleResolve = (d, i) => {
if (!isCatch) {
args[i] = d;
book[i] = 1; // 记录有哪些执行成功了
// 当执行成功的个数和总执行个数相等,执行完毕
if (book.filter(v => v === 1).length === pros.length) {
res(args);
}
}
};
handleCatch = e => {
isCatch = true;
rej(e);
handleCatch = () => {};
};
pros.forEach((item, i) => item.then(d => handleResolve(d, i)).catch(handleCatch));
});
}
static race (pros) {
return new MyPromise((res, rej) => {
let isComplete = false,
isCatch = false,
handleResolve, handleCatch;
handleResolve = d => {
if (!isCatch && !isComplete) {
isComplete = true;
res(d);
}
};
handleCatch = e => {
if (!isComplete) {
isCatch = true;
rej(e);
handleCatch = () => {};
}
};
pros.forEach(item => item.then(handleResolve).catch(handleCatch));
});
}
static reject(msg) {
return new MyPromise((_, reject) => reject(msg));
}
static resolve(msg) {
return new MyPromise(resolve => resolve(msg));
}
}
简单的实现promise
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- Promise的原理 Promise其实内部也有一个defers队列存放事件,.then的事件就在里面,程序开始执...
- 一.Promise的含义和意义 1.什么是PromisePromise是抽象异步处理对象以及对其进行各种操作的组件...
- 执行结果: 改版一 结果值: Promise.catch Promise.all参数:接受一个数组,数组内都是Pr...
- 转载 新京报讯 因演员郑爽近期频繁在自己的APP中晒男友张恒的照片,而引发其大量粉丝脱粉。6月17日,郑爽公开回应...